{"title":"iliazeus","subtitle":"\u0438\u043b\u044c\u044f, \u0438\u043b\u044c \u043d\u0435 \u044f","link":[{"@attributes":{"rel":"self","type":"application\/atom+xml","href":"https:\/\/iliazeus.lol\/atom.xml"}},{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol"}}],"generator":"Zola","updated":"2024-03-20T00:00:00+00:00","id":"https:\/\/iliazeus.lol\/atom.xml","entry":[{"title":"Punk-o-Matic.net Most Rated","published":"2024-03-20T00:00:00+00:00","updated":"2024-03-20T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/punkomatic\/pom-net-most-rated\/"}},"id":"https:\/\/iliazeus.lol\/punkomatic\/pom-net-most-rated\/","content":"<p>These were salvaged with the help of <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/web.archive.org\/web\/20130202172044\/http:\/\/www.punk-o-matic.net\/index.php?option=com_usercontents&amp;task=displayallcontents&amp;mode=mostrated&amp;type=0&amp;Itemid=60\">Internet Archive<\/a>.<\/p>\n<style>main ul li { margin-bottom: 0; list-style-type: none }<\/style>\n<hgroup class=\"punkomatic-song\" id=\"war-machine\">\n  <h3><a class=\"anchor\" href=\"#war-machine\" title=\"link to section\">#<\/a>1. WarMachine<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: XxXxTINOxXxX<\/li>\n      <li>Metal<\/li>\n      <li>Rating: 9.48 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222032211&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=821&amp;Itemid=60\">132 ratings, 149 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(WAR MACHINE)-Bcz-cbt-gbt-gbt- gbt-gcC-acD-abz-gbz-gbt-gbt-gb t-gbt-gbt-gbt-gbt-gbt-ccz-cbF- gbF-gbF-gbF-gbF-gbF-ccz-cbI-gb I-gbI-gbI-gdf-Acz-acBcBby-gby- gby-gby-gby-gby-gby-gby-ecC-ab F-gbF-gbF-gbF-gbI-gbI-gbI-gbI- gbI-gbI-ecA-adu-I,ahaybF-aah-a ah-aahaybYbFah-cahaybF-aah-aah -aahaybYbFah-cagazbE-aag-aag-a agazbXbEag-cagazbE-aag-aag-aag azbXbEag-cpm-cgu-cag-cgG-cag-c gu-cag-cgu-cag-cgu-cag-cgu-cag -cgu-cag-cgu-cag-cgu-cag-cgu-c ag-cagazbE-aag-aag-aagazbXbEag -cagazbE-aag-aag-aagazbXbEag-c agazbE-aag-aag-aagazbXbEag-cab aubz-aab-aab-aabaubSbzab-cabau bz-aab-aab-aabaubSbzab-cah-cah -cah-cah-caf-caf-caf-caf-caf-c af-caf-caf-cag-cag-cag-cag-cgu -cag-cgu-cag-cgu-cah-cgu-cah-c agazbE-aag-aag-aagazbXbEag-cag azbE-aag-aag-aagazbXbEag-cagaz bE-aag-aag-aagazbXbEag-cagazbE -aag-aag-aagazbXbEag-sap-I,-Ba l-cafasbf-aaf-aaf-aafasbsbfaf- cafafbf-aaf-aaf-aafasbsbfaf-ch x-ahz-afV-cae-cgh-cae-cfV-cae- cfV-cae-cfV-cae-cfV-cae-cfV-ca e-cfV-cae-cfV-cae-cfV-cae-cafa sbf-aaf-aaf-aafasbsbfaf-cafasb f-aaf-aaf-aafasbsbfaf-cafasbf- aaf-aaf-aafasbsbfaf-caaanba-aa a-aaa-aaaanbnbaaa-caaanba-aaa- aaa-aaaanbnbaaa-caf-caf-caf-ca f-cad-cad-cad-cad-cad-cad-cad- cad-cae-cae-cae-cae-cfV-cae-cf V-cae-cfV-caf-cfV-caf-cafasbf- aaf-aaf-aafasbsbfaf-cafasbf-aa f-aaf-aafasbsbfaf-cafasbf-aaf- aaf-aafasbsbfaf-cafasbf-aaf-aa f-aafasbsbfaf-caearbe-aae-aae- aaearbrbeae-cam-I,-Baq-caeaxbC -aae-aae-aaeaxbVbCae-caeaxbC-a ae-aae-aaeaxbVbCae-caq-cab-cae -cab-cae-gae-gae-cnb-cnc-cnd-c nc-gae-gae-cnb-cnc-cnd-cnc-cae axbC-aae-aae-aaeaxbVbCae-caeax bC-aae-aae-aaeaxbVbCae-cnb-cnc -cnd-cnc-cacavbA-aac-aac-aacav bTbAac-cacavbA-aac-aac-aacavbT bAac-cap-Aab-cab-cab-cab-cab-c ab-cab-cab-cab-gae-gae-gaa-gaa -caeaxbC-aae-aae-aaeaxbVbCae-c aeaxbC-aae-aae-aaeaxbVbCae-cae axbC-aae-aae-aaeaxbVbCae-Iao-I<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#war-machine\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(WAR MACHINE)-Bcz-cbt-gbt-gbt- gbt-gcC-acD-abz-gbz-gbt-gbt-gb t-gbt-gbt-gbt-gbt-gbt-ccz-cbF- gbF-gbF-gbF-gbF-gbF-ccz-cbI-gb I-gbI-gbI-gdf-Acz-acBcBby-gby- gby-gby-gby-gby-gby-gby-ecC-ab F-gbF-gbF-gbF-gbI-gbI-gbI-gbI- gbI-gbI-ecA-adu-I,ahaybF-aah-a ah-aahaybYbFah-cahaybF-aah-aah -aahaybYbFah-cagazbE-aag-aag-a agazbXbEag-cagazbE-aag-aag-aag azbXbEag-cpm-cgu-cag-cgG-cag-c gu-cag-cgu-cag-cgu-cag-cgu-cag -cgu-cag-cgu-cag-cgu-cag-cgu-c ag-cagazbE-aag-aag-aagazbXbEag -cagazbE-aag-aag-aagazbXbEag-c agazbE-aag-aag-aagazbXbEag-cab aubz-aab-aab-aabaubSbzab-cabau bz-aab-aab-aabaubSbzab-cah-cah -cah-cah-caf-caf-caf-caf-caf-c af-caf-caf-cag-cag-cag-cag-cgu -cag-cgu-cag-cgu-cah-cgu-cah-c agazbE-aag-aag-aagazbXbEag-cag azbE-aag-aag-aagazbXbEag-cagaz bE-aag-aag-aagazbXbEag-cagazbE -aag-aag-aagazbXbEag-sap-I,-Ba l-cafasbf-aaf-aaf-aafasbsbfaf- cafafbf-aaf-aaf-aafasbsbfaf-ch x-ahz-afV-cae-cgh-cae-cfV-cae- cfV-cae-cfV-cae-cfV-cae-cfV-ca e-cfV-cae-cfV-cae-cfV-cae-cafa sbf-aaf-aaf-aafasbsbfaf-cafasb f-aaf-aaf-aafasbsbfaf-cafasbf- aaf-aaf-aafasbsbfaf-caaanba-aa a-aaa-aaaanbnbaaa-caaanba-aaa- aaa-aaaanbnbaaa-caf-caf-caf-ca f-cad-cad-cad-cad-cad-cad-cad- cad-cae-cae-cae-cae-cfV-cae-cf V-cae-cfV-caf-cfV-caf-cafasbf- aaf-aaf-aafasbsbfaf-cafasbf-aa f-aaf-aafasbsbfaf-cafasbf-aaf- aaf-aafasbsbfaf-cafasbf-aaf-aa f-aafasbsbfaf-caearbe-aae-aae- aaearbrbeae-cam-I,-Baq-caeaxbC -aae-aae-aaeaxbVbCae-caeaxbC-a ae-aae-aaeaxbVbCae-caq-cab-cae -cab-cae-gae-gae-cnb-cnc-cnd-c nc-gae-gae-cnb-cnc-cnd-cnc-cae axbC-aae-aae-aaeaxbVbCae-caeax bC-aae-aae-aaeaxbVbCae-cnb-cnc -cnd-cnc-cacavbA-aac-aac-aacav bTbAac-cacavbA-aac-aac-aacavbT bAac-cap-Aab-cab-cab-cab-cab-c ab-cab-cab-cab-gae-gae-gaa-gaa -caeaxbC-aae-aae-aaeaxbVbCae-c aeaxbC-aae-aae-aaeaxbVbCae-cae axbC-aae-aae-aaeaxbVbCae-Iao-I\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"birth-of-a-hero\">\n  <h3><a class=\"anchor\" href=\"#birth-of-a-hero\" title=\"link to section\">#<\/a>2. Birth of a Hero<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: poepoe29<\/li>\n      <li>Hard Rock<\/li>\n      <li>Rating: 9.40 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222031924&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=1910&amp;Itemid=60\">(110 ratings, 114 comments)<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Birth of A Hero)-vcI-abM-gbS- gbM-gbS-ecE-abI-gbI-gbI-gbI-cc Z-ccz-cbM-gbS-gbM-gbS-wci-gci- ccz-cbM-gbS-gbM-gbS-ecE-Z-Z-Z- Z-S,cB-gel-cbp-cdg-acu-abI-acu -ael-cbp-cdg-acu-abI-acu-ael-c bp-cdg-acu-abI-acu-ahR-ghR-cbu -chR-ghR-cbu-abN-ack-cel-cbp-c dg-acu-abI-acu-ael-cbp-cdg-acu -abI-acu-aeq-ccz-cdl-geq-ccz-c dl-ccz-cel-cbp-cdg-acu-abI-acu -ael-cbp-cdg-acu-abI-acu-alo-Z -Z-Z-Z-Q,bM-gcT-caT-ccg-abG-ab g-abG-acT-caT-ccg-abG-abg-abG- acT-caT-ccg-abG-abg-abG-ahs-gh s-caX-chs-ghs-caX-abk-abA-ccT- caT-ccg-abG-abg-abG-acT-caT-cc g-abG-abg-abG-acX-cbK-cck-gcX- cbK-cck-cbK-ccT-caT-ccg-abG-ab g-abG-acT-caT-ccg-abG-abg-abG- acX-Z-Z-Z-Z-Q,cB-gel-cbp-cdg-a cu-abI-acu-alc-biMjF-cjb-aiM-a ii-clc-biMjF-cjb-aiM-aii-coW-g oW-ciY-coW-goW-ciY-ajn-ajF-clc -biMjF-cjb-aiM-aii-clc-biMjF-c jb-aiM-aii-ceq-afceqcz-aeqdXdl -aeq-acz-bdleq-afceqcz-aeqdXdl -aeq-aeN-clc-biMjF-cjb-aiM-aii -clc-biMjF-cjb-aiM-aii-ceq-Z-Z -Z-Z-Q<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#birth-of-a-hero\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Birth of A Hero)-vcI-abM-gbS- gbM-gbS-ecE-abI-gbI-gbI-gbI-cc Z-ccz-cbM-gbS-gbM-gbS-wci-gci- ccz-cbM-gbS-gbM-gbS-ecE-Z-Z-Z- Z-S,cB-gel-cbp-cdg-acu-abI-acu -ael-cbp-cdg-acu-abI-acu-ael-c bp-cdg-acu-abI-acu-ahR-ghR-cbu -chR-ghR-cbu-abN-ack-cel-cbp-c dg-acu-abI-acu-ael-cbp-cdg-acu -abI-acu-aeq-ccz-cdl-geq-ccz-c dl-ccz-cel-cbp-cdg-acu-abI-acu -ael-cbp-cdg-acu-abI-acu-alo-Z -Z-Z-Z-Q,bM-gcT-caT-ccg-abG-ab g-abG-acT-caT-ccg-abG-abg-abG- acT-caT-ccg-abG-abg-abG-ahs-gh s-caX-chs-ghs-caX-abk-abA-ccT- caT-ccg-abG-abg-abG-acT-caT-cc g-abG-abg-abG-acX-cbK-cck-gcX- cbK-cck-cbK-ccT-caT-ccg-abG-ab g-abG-acT-caT-ccg-abG-abg-abG- acX-Z-Z-Z-Z-Q,cB-gel-cbp-cdg-a cu-abI-acu-alc-biMjF-cjb-aiM-a ii-clc-biMjF-cjb-aiM-aii-coW-g oW-ciY-coW-goW-ciY-ajn-ajF-clc -biMjF-cjb-aiM-aii-clc-biMjF-c jb-aiM-aii-ceq-afceqcz-aeqdXdl -aeq-acz-bdleq-afceqcz-aeqdXdl -aeq-aeN-clc-biMjF-cjb-aiM-aii -clc-biMjF-cjb-aiM-aii-ceq-Z-Z -Z-Z-Q\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"the-seductress\">\n  <h3><a class=\"anchor\" href=\"#the-seductress\" title=\"link to section\">#<\/a>3. The Seductress<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Dkoopa<\/li>\n      <li>Classic Rock<\/li>\n      <li>Rating: 9.59 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20130202172044&#x2F;http:&#x2F;&#x2F;www.punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=482&amp;Itemid=60\">90 ratings, 100 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(The Seductress)-Cdu-ccX-ccY-c cX-ccY-ccY-ccY-ccS-ccS-ccB-acB -acB-acB-adf-abv-gbv-gdf-fcDcE -acE-acE-adf-abv-gbv-gbv-gbv-U dg-kdu-caH- fcIaH-fczcB-acB -acB-acB-acB-acB-acB-acB-adf-e cA-adf-ecA-adf-ecA-adf-kdu-caH -fcIaH-fczcB-acB-acB-acB-acB-a cB-acB-acB-adf-Z-Z-J,-cjC- eif-hkcjC-diUif-fkcjC-fiUhT-ch T-bjXjq-cjq-biPhT-chT-bjXjq-cj q-biPnh-ant-ant-ant-cnTnWnT-cn pnqnt-ant-ant-cnTnWnT-cnpnqnt- ant-ant- cnTnWnT-cnpnqnt-an t-ant-cnTnWnT-dbqap-bcOcg-bbqa p-bcOcg-bbqap-bcOcg-bbqap-bcOc g-bbqap-bcOcg-bbqhT-chT-bjXjq- cjq-biPhT-chT-bjXjq- cjq-bi PhT-chT-bjXjq-cjq-biPih-gjC-fi PiP-aiA-ahW-acHjXjX-ajt-ciPiAh T-chT-chT-chT-bjXjq-cjq-biPhT- chT-bjXjq-cjq-bbqap-bcOcg-bbqa p- bcOcg-bbqap-bcOcg-bbqap- bcOcg-bbqdVeoeJ-Z-Z-b,dhdcdUdP dhdcdUdPdhdcdUdPdhdcdUdPdhdcdU dPdhdcdUdPdhdcdUdPdhdcdUdPdhak -gac-aaP-abp- abPePdc-adP-a ep-aePdPac-aaP-abp-abPePdc-adP -aep-aePdPhF-aac-aaP-abp-abP-a ac-aaP-abp-abP-aakacaXaPbxbpbW -aakacaXaPbxbpbW-aac-aaP- a bp-abP-aac-aaP-abp-abP-aac-aaP -abp-abP-aac-aaP-abp-abP-aak-c bx-cak-cbx-cak-cbx-cak-cbx-cak -cbx-cac-aaP-abp-abPePdc-adP-a ep- aePdPac-aaP-abp-abP-adc -adP-aep-aeP-aac-aaP-abp-abPeP dc-adP-aep-aePdPac-aaP-abp-abP -adc-adP-aep-aeP-aac-aaP-abp-a bP-adc-adP-aep- aeP-adc-adP -aep-aeP-aac-aaP-abp-abP-adc-a dP-aep-aeP-aac-aaP-abp-abPePdc -adP-aep-aePdX-Z-Z-K,-aap-abu- acg-acS-aap-abu-acg-acS-aap- abu-acg-acS-aap-abu-acg-acS- aap-abu-acg-acS-aae-abj-abV-ac H-aae-abj-abV-acH-aae-abj-abV- acH-aae-abj-abV-acH-acSdXae-ab j-abV-acH- aae-abj-abV-acH- aapaebubjcgbVcQ-aapaebubjcgbVc Qmv-akg-amv-akgmB-aae-abj-abV- acHmv-akg-amv-akgmB-aae-abj-ab V-acHmv-akg-amv-akgmB- cmq- cmx-anU-cnq-djC-eiUif-fmv-akg- amv-akgmB-cmq-cmx-anU-cnq-djC- eiUif-gih-gif-fjXjE-gif-sch-ca e-abj-abV-acH-aae-abj-abV-acH- aae- abj-abV-acH-aae-abj-ab V-acHmv-akg-amv-akgmB-cmq-cmx- anU-cnq-djC-eiUnh-aif-Z-Z-b<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#the-seductress\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(The Seductress)-Cdu-ccX-ccY-c cX-ccY-ccY-ccY-ccS-ccS-ccB-acB -acB-acB-adf-abv-gbv-gdf-fcDcE -acE-acE-adf-abv-gbv-gbv-gbv-U dg-kdu-caH- fcIaH-fczcB-acB -acB-acB-acB-acB-acB-acB-adf-e cA-adf-ecA-adf-ecA-adf-kdu-caH -fcIaH-fczcB-acB-acB-acB-acB-a cB-acB-acB-adf-Z-Z-J,-cjC- eif-hkcjC-diUif-fkcjC-fiUhT-ch T-bjXjq-cjq-biPhT-chT-bjXjq-cj q-biPnh-ant-ant-ant-cnTnWnT-cn pnqnt-ant-ant-cnTnWnT-cnpnqnt- ant-ant- cnTnWnT-cnpnqnt-an t-ant-cnTnWnT-dbqap-bcOcg-bbqa p-bcOcg-bbqap-bcOcg-bbqap-bcOc g-bbqap-bcOcg-bbqhT-chT-bjXjq- cjq-biPhT-chT-bjXjq- cjq-bi PhT-chT-bjXjq-cjq-biPih-gjC-fi PiP-aiA-ahW-acHjXjX-ajt-ciPiAh T-chT-chT-chT-bjXjq-cjq-biPhT- chT-bjXjq-cjq-bbqap-bcOcg-bbqa p- bcOcg-bbqap-bcOcg-bbqap- bcOcg-bbqdVeoeJ-Z-Z-b,dhdcdUdP dhdcdUdPdhdcdUdPdhdcdUdPdhdcdU dPdhdcdUdPdhdcdUdPdhdcdUdPdhak -gac-aaP-abp- abPePdc-adP-a ep-aePdPac-aaP-abp-abPePdc-adP -aep-aePdPhF-aac-aaP-abp-abP-a ac-aaP-abp-abP-aakacaXaPbxbpbW -aakacaXaPbxbpbW-aac-aaP- a bp-abP-aac-aaP-abp-abP-aac-aaP -abp-abP-aac-aaP-abp-abP-aak-c bx-cak-cbx-cak-cbx-cak-cbx-cak -cbx-cac-aaP-abp-abPePdc-adP-a ep- aePdPac-aaP-abp-abP-adc -adP-aep-aeP-aac-aaP-abp-abPeP dc-adP-aep-aePdPac-aaP-abp-abP -adc-adP-aep-aeP-aac-aaP-abp-a bP-adc-adP-aep- aeP-adc-adP -aep-aeP-aac-aaP-abp-abP-adc-a dP-aep-aeP-aac-aaP-abp-abPePdc -adP-aep-aePdX-Z-Z-K,-aap-abu- acg-acS-aap-abu-acg-acS-aap- abu-acg-acS-aap-abu-acg-acS- aap-abu-acg-acS-aae-abj-abV-ac H-aae-abj-abV-acH-aae-abj-abV- acH-aae-abj-abV-acH-acSdXae-ab j-abV-acH- aae-abj-abV-acH- aapaebubjcgbVcQ-aapaebubjcgbVc Qmv-akg-amv-akgmB-aae-abj-abV- acHmv-akg-amv-akgmB-aae-abj-ab V-acHmv-akg-amv-akgmB- cmq- cmx-anU-cnq-djC-eiUif-fmv-akg- amv-akgmB-cmq-cmx-anU-cnq-djC- eiUif-gih-gif-fjXjE-gif-sch-ca e-abj-abV-acH-aae-abj-abV-acH- aae- abj-abV-acH-aae-abj-ab V-acHmv-akg-amv-akgmB-cmq-cmx- anU-cnq-djC-eiUnh-aif-Z-Z-b\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"zelda-tribute\">\n  <h3><a class=\"anchor\" href=\"#zelda-tribute\" title=\"link to section\">#<\/a>4. Zelda Tribute<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: eliatriedes<\/li>\n      <li>Real Band Cover<\/li>\n      <li>Rating: 9.95 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20130202172044&#x2F;http:&#x2F;&#x2F;www.punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=4681&amp;Itemid=60\">81 ratings, 92 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Zelda Tribute)-pdu-ccm-gbZ-gb Z-gbZ-gbZ-ccz-acz-acl-gcl-gcl- gcl-gcl-gcl-gdg-cdocP-adocP-ad ocP-adt-bcL-ccL-ccL-ccL-ccL-cc L-ccL-bcL- bcL-bcL-ccL-ccLd g-adu-ccQ-ccQ-ccQ-bcQ-ccQ-ccQ- ccQ-ccQ-ccQ-ccQ-ccQ-bdg-bdg-bd gdgdgdg-cdu-caD-gaD-gaD-gaq-ca s-acJ-adgcP-bdgcP-bdgcP- bd g-cdg-adg-bdg-Z-Z-Y,cz-cbN-cbb -caI-gcl-ccl-ccl-cbz-caN-cdq-c cE-ccl-ccX-caD-abpcbczcl-bbz-c aN-cau-caN-cau-caN-cau-ccE-ccl -ccX-caD- abpcbbu-cbu-bap-b cg-bdX-bbg-bab-bcX-bdJ-bbg-bab -bcX-bdJ-bcX-bcE-bbg-bab-bbS-b dJ-bbu-ecX-bdJ-bbg-cbg-abS-bdJ -bbg-bbg-bcX-bdJ-bbg-bab -b bS-bdJ-bbg-bbu-bbubNcgco-cco-c co-cbC-caQ-cdt-ccH-cco-cda-cax -abjbVcz-cbN-cbb-caI-ccz-abb-b aI-Z-Z-Y,bK-cbk-caK-cax-gbC-cb A-abC-abC -cbc-caC-ccp-cbP- cbC-ccc-cat-aaTbtbC-cbc-caC-ca p-caC-cap-caC-cap-cbP-cbC-ccc- cat-aaTbtaX-caX-bak-bbx-bcK-ba N-baa-bca-bcA-baN-baa- bca- bcA-bca-bbN-baN-baa-bbn-bcA-ba X-eca-bcA-baN-caN-abn-bcA-baN- baN-bca-bcA-baN-baa-bbn-bcA-ba N-baX-baXbkbxbC-cbC-cbC-cbc-ca C-ccp- cbP-cbC-ccc-cap-aaPb pbK-cbk-caK-cax-cbK-aaK-bdx-ca x-Z-Z-U,jR-aiujRjn-cjR-aiJjRjC -gcB-gczaI-ackfc-bjnjR-ajbixjk iu-aiulciJ-aiukyiu- akKkjif -aiYip-cczaI-ackfc-bjbjR-bdEdl iu-aiuiJ-bdEdliu-afcfv-bdEdlfc -akZlo-biJiukK-aoDkjif-aiYip-c iY-nkZiY-akZkg-aiYkZ-dkZiY-akZ kg- aiYkZ-dkZif-biJ-aifkZ-b pu-bpu-bpu-ajCiY-diYiY-biJ-ajC iY-bkZ-bkv-apukv-akZpu-diYiY-b iJ-ajCiY-akZkZ-bkv-bkg-ajCiY-h cB-gczaI-ackiu- bjbjR-ajbix jkiu-aiulciJ-aeNkyiu-alckjif-a iYii-aiu-ajR-aiujRjn-cjR-aiJjR jC-ciu-aiJ-biu-Z-Z-Y<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#zelda-tribute\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Zelda Tribute)-pdu-ccm-gbZ-gb Z-gbZ-gbZ-ccz-acz-acl-gcl-gcl- gcl-gcl-gcl-gdg-cdocP-adocP-ad ocP-adt-bcL-ccL-ccL-ccL-ccL-cc L-ccL-bcL- bcL-bcL-ccL-ccLd g-adu-ccQ-ccQ-ccQ-bcQ-ccQ-ccQ- ccQ-ccQ-ccQ-ccQ-ccQ-bdg-bdg-bd gdgdgdg-cdu-caD-gaD-gaD-gaq-ca s-acJ-adgcP-bdgcP-bdgcP- bd g-cdg-adg-bdg-Z-Z-Y,cz-cbN-cbb -caI-gcl-ccl-ccl-cbz-caN-cdq-c cE-ccl-ccX-caD-abpcbczcl-bbz-c aN-cau-caN-cau-caN-cau-ccE-ccl -ccX-caD- abpcbbu-cbu-bap-b cg-bdX-bbg-bab-bcX-bdJ-bbg-bab -bcX-bdJ-bcX-bcE-bbg-bab-bbS-b dJ-bbu-ecX-bdJ-bbg-cbg-abS-bdJ -bbg-bbg-bcX-bdJ-bbg-bab -b bS-bdJ-bbg-bbu-bbubNcgco-cco-c co-cbC-caQ-cdt-ccH-cco-cda-cax -abjbVcz-cbN-cbb-caI-ccz-abb-b aI-Z-Z-Y,bK-cbk-caK-cax-gbC-cb A-abC-abC -cbc-caC-ccp-cbP- cbC-ccc-cat-aaTbtbC-cbc-caC-ca p-caC-cap-caC-cap-cbP-cbC-ccc- cat-aaTbtaX-caX-bak-bbx-bcK-ba N-baa-bca-bcA-baN-baa- bca- bcA-bca-bbN-baN-baa-bbn-bcA-ba X-eca-bcA-baN-caN-abn-bcA-baN- baN-bca-bcA-baN-baa-bbn-bcA-ba N-baX-baXbkbxbC-cbC-cbC-cbc-ca C-ccp- cbP-cbC-ccc-cap-aaPb pbK-cbk-caK-cax-cbK-aaK-bdx-ca x-Z-Z-U,jR-aiujRjn-cjR-aiJjRjC -gcB-gczaI-ackfc-bjnjR-ajbixjk iu-aiulciJ-aiukyiu- akKkjif -aiYip-cczaI-ackfc-bjbjR-bdEdl iu-aiuiJ-bdEdliu-afcfv-bdEdlfc -akZlo-biJiukK-aoDkjif-aiYip-c iY-nkZiY-akZkg-aiYkZ-dkZiY-akZ kg- aiYkZ-dkZif-biJ-aifkZ-b pu-bpu-bpu-ajCiY-diYiY-biJ-ajC iY-bkZ-bkv-apukv-akZpu-diYiY-b iJ-ajCiY-akZkZ-bkv-bkg-ajCiY-h cB-gczaI-ackiu- bjbjR-ajbix jkiu-aiulciJ-aeNkyiu-alckjif-a iYii-aiu-ajR-aiujRjn-cjR-aiJjR jC-ciu-aiJ-biu-Z-Z-Y\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"a-blackened-nostalgia\">\n  <h3><a class=\"anchor\" href=\"#a-blackened-nostalgia\" title=\"link to section\">#<\/a>5. A Blackened Nostalgia (My Past In Ashes)<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Nocturne<\/li>\n      <li>Punk<\/li>\n      <li>Rating: 9.94 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20130202172044&#x2F;http:&#x2F;&#x2F;www.punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=7189&amp;Itemid=60\">80 ratings, 92 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(A Blackened Nostalgia)-Ddu-cd g-cdu-cbY-gbY-gbY-gbY-gbY-gbY- gbY-gbY-gbP-gbP-gbP-gbP-edv-aa D-gaD-gaD-gaD-daD-bcF-acF-aaX- ccF-acF-aaX-ccF-acF-aaT-ccF-ac F-abt-cdf-Gdu-ccJ-abU-gbV-gbG- caD-cah-cbt-ccC-abP-edv-aaD-ga D-baDaD-caD-ecF-aan-cbLbLbLbLd pczdvczcF-acF-aaT-ccF-acF-abt- caD-gbt-gbG-ecF-aan-ccX-cdf-Z- s,bu-acg-acS-cmm-ciJlG-bbu-aap -acS-acg-abu-acg-acS-ecS-gcS-c bu-cmv-bmS-cmHcS-cbu-cmv-bmH-c iJcS-cbu-cmv-bmSlG-ccS-cbu-cmv -bmS-blO-abu-acg-acS-ccS-acg-a mz-cbu-acg-acS-ccS-acg-amB-cbf -abR-acD-cmm-emi-abf-abR-acD-c bf-abR-acD-ccP-adB-abjbiaeadiG -aiV-ajqiMixhTcPcMdBjrbjiMaehT iG-aiV-ajqiMixhTcS-gcU-cbw-cmv -bmS-cmHcT-cbv-cmv-bmH-ciJcE-c bg-cmv-bmSlG-ccH-cbj-cmv-bmS-b lO-ccS-acg-amB-cbf-abR-acD-cmm -emi-abf-abR-acD-cbf-abR-acD-c cQixcehTcPcMdBjrbjiMaehTiG-aiV -ajqiMixhTbf-abR-acD-cmm-emi-a bf-abR-acD-cbf-abR-acS-gbu-acg -acS-cmm-ciJlG-bbu-aap-acS-acg -abu-acg-acS-alE-glE-glE-glE-a iJ-k,bX-cbX-cbX-cbX-caX-ebx-ab X-cbX-edK-geX-cbX-ceX-cbX-ceX- cbX-ceX-cbX-ceX-cbX-ceX-caX-ce X-cbX-ceX-cbX-caX-abx-abX-caX- aak-abX-caX-abx-abX-caX-aak-ab X-caN-abn-abN-caN-abn-abN-abn- aaN-abn-abN-caN-abn-abN-cbV-ab v-aaPaOacabbV-abv-aaPaOacabbV- abv-aaPaOacabbV-abv-aaPaOacabc K-geZ-cbZ-ceZ-cbZ-ceY-cbY-ceY- cbY-ceP-cbP-ceP-caP-ceP-cbP-ce P-cbQ-aaQ-abr-aaX-aak-abX-caN- abn-abN-caN-abn-abN-abn-aaN-ab n-abN-caN-abn-abN-cbW-abw-abV- abv-aaPaOacabbV-abv-aaPaOacaba N-abn-abN-caN-abn-abN-abn-aaN- abn-abN-caN-abn-abX-gbX-cbX-cb X-cbX-caX-ebx-abX-cbX-caX-abx- abX-caX-abx-abX-caX-abx-abX-ca X-abx-abZ-g,mB-ciyhUkOkzbu-acg -acS-cmo-cmD-alE-gkZ-akK-apu-g mv-bmR-dcS-cbu-cmv-bmT-cixcS-c bu-cmv-bmRlz-ccS-clL-cmv-bmR-d cS-cbu-alN-acS-adE-amS-cbu-aap -acS-ccS-adE-amF-cbu-aap-acS-c mg-cixhTkNkybf-abR-acD-abR-amD lM-clMlE-eiJ-ckW-aic-aixhTkNky cP-adB-abjbiaeadkW-aic-aixhTkN kycPcMdBjrixhTkNkyiJ-gmv-bmR-d cU-cbw-cmv-bmT-cixcT-cbv-cmv-b mRlz-ccE-clL-cmv-bmR-dcI-cbk-a lN-cbu-aap-acS-amE-amg-cixhTkN kybf-abR-acD-abR-amDlM-clMlE-e iJ-caGjqdViMkW-aic-aixhTkNkycP cMdBjrixhTkNkymg-cixhTkNkybf-a bR-acD-abR-amDlM-clMlE-eiJ-gmB -ciyhUkOkzbu-acg-acS-cmo-cmD-a lE-gmm-dlE-flE-glE-gpu-i<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#a-blackened-nostalgia\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(A Blackened Nostalgia)-Ddu-cd g-cdu-cbY-gbY-gbY-gbY-gbY-gbY- gbY-gbY-gbP-gbP-gbP-gbP-edv-aa D-gaD-gaD-gaD-daD-bcF-acF-aaX- ccF-acF-aaX-ccF-acF-aaT-ccF-ac F-abt-cdf-Gdu-ccJ-abU-gbV-gbG- caD-cah-cbt-ccC-abP-edv-aaD-ga D-baDaD-caD-ecF-aan-cbLbLbLbLd pczdvczcF-acF-aaT-ccF-acF-abt- caD-gbt-gbG-ecF-aan-ccX-cdf-Z- s,bu-acg-acS-cmm-ciJlG-bbu-aap -acS-acg-abu-acg-acS-ecS-gcS-c bu-cmv-bmS-cmHcS-cbu-cmv-bmH-c iJcS-cbu-cmv-bmSlG-ccS-cbu-cmv -bmS-blO-abu-acg-acS-ccS-acg-a mz-cbu-acg-acS-ccS-acg-amB-cbf -abR-acD-cmm-emi-abf-abR-acD-c bf-abR-acD-ccP-adB-abjbiaeadiG -aiV-ajqiMixhTcPcMdBjrbjiMaehT iG-aiV-ajqiMixhTcS-gcU-cbw-cmv -bmS-cmHcT-cbv-cmv-bmH-ciJcE-c bg-cmv-bmSlG-ccH-cbj-cmv-bmS-b lO-ccS-acg-amB-cbf-abR-acD-cmm -emi-abf-abR-acD-cbf-abR-acD-c cQixcehTcPcMdBjrbjiMaehTiG-aiV -ajqiMixhTbf-abR-acD-cmm-emi-a bf-abR-acD-cbf-abR-acS-gbu-acg -acS-cmm-ciJlG-bbu-aap-acS-acg -abu-acg-acS-alE-glE-glE-glE-a iJ-k,bX-cbX-cbX-cbX-caX-ebx-ab X-cbX-edK-geX-cbX-ceX-cbX-ceX- cbX-ceX-cbX-ceX-cbX-ceX-caX-ce X-cbX-ceX-cbX-caX-abx-abX-caX- aak-abX-caX-abx-abX-caX-aak-ab X-caN-abn-abN-caN-abn-abN-abn- aaN-abn-abN-caN-abn-abN-cbV-ab v-aaPaOacabbV-abv-aaPaOacabbV- abv-aaPaOacabbV-abv-aaPaOacabc K-geZ-cbZ-ceZ-cbZ-ceY-cbY-ceY- cbY-ceP-cbP-ceP-caP-ceP-cbP-ce P-cbQ-aaQ-abr-aaX-aak-abX-caN- abn-abN-caN-abn-abN-abn-aaN-ab n-abN-caN-abn-abN-cbW-abw-abV- abv-aaPaOacabbV-abv-aaPaOacaba N-abn-abN-caN-abn-abN-abn-aaN- abn-abN-caN-abn-abX-gbX-cbX-cb X-cbX-caX-ebx-abX-cbX-caX-abx- abX-caX-abx-abX-caX-abx-abX-ca X-abx-abZ-g,mB-ciyhUkOkzbu-acg -acS-cmo-cmD-alE-gkZ-akK-apu-g mv-bmR-dcS-cbu-cmv-bmT-cixcS-c bu-cmv-bmRlz-ccS-clL-cmv-bmR-d cS-cbu-alN-acS-adE-amS-cbu-aap -acS-ccS-adE-amF-cbu-aap-acS-c mg-cixhTkNkybf-abR-acD-abR-amD lM-clMlE-eiJ-ckW-aic-aixhTkNky cP-adB-abjbiaeadkW-aic-aixhTkN kycPcMdBjrixhTkNkyiJ-gmv-bmR-d cU-cbw-cmv-bmT-cixcT-cbv-cmv-b mRlz-ccE-clL-cmv-bmR-dcI-cbk-a lN-cbu-aap-acS-amE-amg-cixhTkN kybf-abR-acD-abR-amDlM-clMlE-e iJ-caGjqdViMkW-aic-aixhTkNkycP cMdBjrixhTkNkymg-cixhTkNkybf-a bR-acD-abR-amDlM-clMlE-eiJ-gmB -ciyhUkOkzbu-acg-acS-cmo-cmD-a lE-gmm-dlE-flE-glE-gpu-i\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"theoretically-incorrect\">\n  <h3><a class=\"anchor\" href=\"#theoretically-incorrect\" title=\"link to section\">#<\/a>6. Theoretically Incorrect<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Agent Ohoolahan<\/li>\n      <li>Hard Rock<\/li>\n      <li>Rating: 9.93 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20130202172044&#x2F;http:&#x2F;&#x2F;www.punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=15534&amp;Itemid=60\">73 ratings, 77 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Theoretically Incorrect)da-ad cdsda-adc-ada-adc-adc-bcTaf-ga n-acC-acD-acE-abM-cbP-cbI-gbM- cbP-cbI-ecE-abK-ecG-abH-ecB-ab K-gbL-ecA-acX-ccY-ccY-ccBcBcE- aab-gag-gbD-gbA-gcm-acf-abHbHc p-acm-acf-abHbHcp-abK-ccz-acIc Zcz-cbK-gbL-ecA-aab-gac-gbD-gb A-ccG-acJ-acX-ccY-acB-acX-ccY- acE-abx-abx-aby-aby-aah-bcEak- cbJ-gbL-ccC-acD-acBdfcBcIcE-ac A-acBdfcEdfcz-ccBdfcBcIcE-acA- acBdfcEdfcE-aczcBcz-cbK-ecG-ab H-ecB-aab-gag-gbD-gbA-ccG-ccG- acF-acG-acF-acD-acE-adg-cds-cd s-cds-cdu-Z-g,bw-cdn-acTchbw-c ci-cbw-cdn-acTchci-cch-ciY-ckg -cif-ciJ-aiYiJap-cfv-cdl-ccS-c ev-cdJ-ccX-cdJ-ceA-cdO-cdc-add cWdI-caa-ccW-ccD-cpr-ckj-ciM-a ix-akj-ckN-ckj-ciM-aix-akj-ckU -apm-aeDakeAcWcH-cezbpbRddfRfR fRbgae-ceL-geA-cdO-cdc-addcWdI -ckj-ciM-aix-akj-ckN-ckj-ciM-a ix-akjiaixhWdI-apn-abSbUbXcfab adagaocXcZdcdkcE-ceBeydddacKdP cKdPdb-bcIdI-ccg-cap-cdl-ccS-c dj-adV-aey!!dM!!dj-acQ-aeueFdI dTdj-adV-aey!!dM!!dj-acQ-aacao ab-aab-cev-cdJ-ccX-cdJ-ckj-ciM jqiMixkj-ckN-ckj-ciM-aix-akj-c kU-apm-adl-cdX-cap-gih-clb-cih -Z-k,-ohFeVdTevdGdVdUdIdHbVdGe vdGdV-adA-aga-cgp-aeP-acc-bdPd C-ahF-aga-cgp-aeP-acc-bdPdC-ah F-add-acd-acD-cce-abr-acE-caa- aca-acA-ccf-abr-acA-cdf-aesdSc a-ceQ-cbV-abN-aboaHabbudb-cdN- aeUendA-cboaHabbudb-cdN-aeudNd A-cfQ-bdacQbSdNcNfW-afW-abSbqa TaIfR-baAak-gaa-aca-acA-ccf-ab r-acA-cboaHabbudb-cdN-aeUendA- cboaHabbudb-cdN-aeudNdA-ccabxe pdUda-cccdXdadAdA-acN-agu-ccCd FdQdAhj-adc-acA-cendCcCcgdc-cd Q-aepdSdA-cenewdAcJdd-acD-aene wdAcIda-adN-aenewdAcJdd-acD-ae pewdCcIaa-aaN-aaa-cdd-acd-acD- cce-abr-acE-cboaHabbudb-cdN-ae UendA-cboaHabbudb-cdN-aeudNdA- cck-ackdkdK-acK-adk-uhE-Z-e,ar -acU-aci-car-acU-adn-caq-acT-a ci-caq-acT-adm-cap-cfv-cdl-ccS -ciY-ckg-cif-ciJ-aiYiJifkg-bjC iYkgifiY-bkgjC-aiYkZhTjX-bjuiT kciciP-bkcjz-aiMixnj-fnLiyiNiy hUjV-cibiGiUiEhW-ciQ-aiBiTiA-c ibiGiUiEhW-ciQ-aiBiTjt-biGig-c lp-biZig-ciK-blaig-ckgjCiYiJiM -ahT-ahTjX-bjuiTkciciP-bkcjz-a iMixibiGiUiEhW-ciQ-aiBiTiA-cib iGjyiEhW-ciQ-aiBiTjt-aiz-akkjr iyhUiNnl-aiy-akOkkiyhU-aldiNiP ib-biPkV-bkmiF-aiUiGiPiFkNkv-a iJiYiYiJifpuif-aiJifloifkgjCjx iYiJiTjxiYiJiTjxiYiJiTiY-cjxiY iJiTjxiYiJiTjxiYiJiTif-gifkg-b jCiYkgifiY-bkgjC-aiYkZibiGiUiE hW-ciQ-aiBiTiA-cibiGiUiEhW-ciQ -aiBiTjt-aiJ-aif-biYiJ-akZiJif iY-aiJif-ckx-ciL-cki-Z-k<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#theoretically-incorrect\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Theoretically Incorrect)da-ad cdsda-adc-ada-adc-adc-bcTaf-ga n-acC-acD-acE-abM-cbP-cbI-gbM- cbP-cbI-ecE-abK-ecG-abH-ecB-ab K-gbL-ecA-acX-ccY-ccY-ccBcBcE- aab-gag-gbD-gbA-gcm-acf-abHbHc p-acm-acf-abHbHcp-abK-ccz-acIc Zcz-cbK-gbL-ecA-aab-gac-gbD-gb A-ccG-acJ-acX-ccY-acB-acX-ccY- acE-abx-abx-aby-aby-aah-bcEak- cbJ-gbL-ccC-acD-acBdfcBcIcE-ac A-acBdfcEdfcz-ccBdfcBcIcE-acA- acBdfcEdfcE-aczcBcz-cbK-ecG-ab H-ecB-aab-gag-gbD-gbA-ccG-ccG- acF-acG-acF-acD-acE-adg-cds-cd s-cds-cdu-Z-g,bw-cdn-acTchbw-c ci-cbw-cdn-acTchci-cch-ciY-ckg -cif-ciJ-aiYiJap-cfv-cdl-ccS-c ev-cdJ-ccX-cdJ-ceA-cdO-cdc-add cWdI-caa-ccW-ccD-cpr-ckj-ciM-a ix-akj-ckN-ckj-ciM-aix-akj-ckU -apm-aeDakeAcWcH-cezbpbRddfRfR fRbgae-ceL-geA-cdO-cdc-addcWdI -ckj-ciM-aix-akj-ckN-ckj-ciM-a ix-akjiaixhWdI-apn-abSbUbXcfab adagaocXcZdcdkcE-ceBeydddacKdP cKdPdb-bcIdI-ccg-cap-cdl-ccS-c dj-adV-aey!!dM!!dj-acQ-aeueFdI dTdj-adV-aey!!dM!!dj-acQ-aacao ab-aab-cev-cdJ-ccX-cdJ-ckj-ciM jqiMixkj-ckN-ckj-ciM-aix-akj-c kU-apm-adl-cdX-cap-gih-clb-cih -Z-k,-ohFeVdTevdGdVdUdIdHbVdGe vdGdV-adA-aga-cgp-aeP-acc-bdPd C-ahF-aga-cgp-aeP-acc-bdPdC-ah F-add-acd-acD-cce-abr-acE-caa- aca-acA-ccf-abr-acA-cdf-aesdSc a-ceQ-cbV-abN-aboaHabbudb-cdN- aeUendA-cboaHabbudb-cdN-aeudNd A-cfQ-bdacQbSdNcNfW-afW-abSbqa TaIfR-baAak-gaa-aca-acA-ccf-ab r-acA-cboaHabbudb-cdN-aeUendA- cboaHabbudb-cdN-aeudNdA-ccabxe pdUda-cccdXdadAdA-acN-agu-ccCd FdQdAhj-adc-acA-cendCcCcgdc-cd Q-aepdSdA-cenewdAcJdd-acD-aene wdAcIda-adN-aenewdAcJdd-acD-ae pewdCcIaa-aaN-aaa-cdd-acd-acD- cce-abr-acE-cboaHabbudb-cdN-ae UendA-cboaHabbudb-cdN-aeudNdA- cck-ackdkdK-acK-adk-uhE-Z-e,ar -acU-aci-car-acU-adn-caq-acT-a ci-caq-acT-adm-cap-cfv-cdl-ccS -ciY-ckg-cif-ciJ-aiYiJifkg-bjC iYkgifiY-bkgjC-aiYkZhTjX-bjuiT kciciP-bkcjz-aiMixnj-fnLiyiNiy hUjV-cibiGiUiEhW-ciQ-aiBiTiA-c ibiGiUiEhW-ciQ-aiBiTjt-biGig-c lp-biZig-ciK-blaig-ckgjCiYiJiM -ahT-ahTjX-bjuiTkciciP-bkcjz-a iMixibiGiUiEhW-ciQ-aiBiTiA-cib iGjyiEhW-ciQ-aiBiTjt-aiz-akkjr iyhUiNnl-aiy-akOkkiyhU-aldiNiP ib-biPkV-bkmiF-aiUiGiPiFkNkv-a iJiYiYiJifpuif-aiJifloifkgjCjx iYiJiTjxiYiJiTjxiYiJiTiY-cjxiY iJiTjxiYiJiTjxiYiJiTif-gifkg-b jCiYkgifiY-bkgjC-aiYkZibiGiUiE hW-ciQ-aiBiTiA-cibiGiUiEhW-ciQ -aiBiTjt-aiJ-aif-biYiJ-akZiJif iY-aiJif-ckx-ciL-cki-Z-k\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"running-from-your-past\">\n  <h3><a class=\"anchor\" href=\"#running-from-your-past\" title=\"link to section\">#<\/a>7. Running From Your Past<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: ScaleTheSummit<\/li>\n      <li>Alternative<\/li>\n      <li>Rating: 9.13 &#x2F; 10.00<\/li>\n      \n        <li>69 ratings, 71 comments<\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Running From Your Past)dododo dododododododododododododododo dlav-gav-gat-gau-ecBcBaC-gaC-g aD-gaJ-gcX-ccY-ccY-ccz-ccj-gcj -fcH-acB-aaH-gaH-ecC-aaJ-gaJ-c cBcBcBcDby-bcBdf-adf-adf-acB-a df-adf-adf-acC-adf-ncz-ccF-aat -gau-ccBcBcBcDaa-gaa-ccD-acC-a ag-gag-ccBcBcBcDdg-Z-Z-Z-R,eq- ibw-gbibzbBcWcqbgbibycqbzbBcWc qbgbibydcbzbBcWcqbgbibycqbzbBc WcqbgbihJ-aby-acWckbf-abyckby- acWckbf-aebcWby-acWckbf-abyckb y-acWckbf-aebdpdl-gja-gdldj-ab rczcx-aaFdldj-abrdXdV-acw-acz- abD-acWckbk-abyckbD-acWckbk-ae bcWbE-acWckbl-abyckbE-acWckbl- aebdpcWdIebeueo-adV-aeo-afa-ae o-adV-aeo-afa-aeq-jkx-gdg-abzb BcWcqbgbibycqbzbBcWcqbgbipm-ab D-acWckbk-abyckbD-acWckbk-aebc WbEbGcWckblbnbyckbEbGcWckblbne bdpdl-Z-Z-Z-R,cX-iaZ-gaOcX-adX dxck-acKdxcX-adXdxck-acKdXcX-a dXdxck-acKdxcX-adXdxck-aekdXcN -adNdncacacAdncN-adNdncacaeAdN cN-adNdncacacAdncN-adNdncacaeA eahphh-agY-acIcAdnhphh-agY-acI cNcacUhpchcAhh-acUdvcUhpchcAgG -acHdn-aeF-acN-adNdncacacAdncN -adNdncacaeAdNcN-adNdncacacAdn cN-adNdncacaeAeadNeneAeNcW-acJ -acW-adw-acW-acJ-acW-adw-acX-j cm-gcg-acX-adXdxck-acKdxcX-adX dxck-aekdXcN-adNdncacacAdncN-a dNdncacaeAdNcN-adNdncacacAdncN -adNdncacaeAeadX-Z-Z-Z-R,oM-al fkOkkilldkPkmpailkNkjkNiiiMiPi M-alclfiMiikjkmkNiilclfiMiikjk mkNiMlclfiMiikjkmkNiilclfiMiik jkmjbiMlclhiMiikjkokNiilclhiMi ikjkojFiMlclhiMiikjkokNiilclhi MiikjkojFjbiY-gkx-giYiN-biuij- biYiN-bjRjG-ajI-alg-alclhiMiik jkokNiilclhiMiikjkojFiMlclhiMi ikjkokNiilclhiMiikjkojFjbiMjqj FjUoRoooQopoApaoPogoqoGoooQpgp hoF-aoM-alfkOkkilldkPkmpailkNk jkNiiiMiPiM-aiTiMlclfiMiikjkmk NiilclfiMiikjkmjbiMlclhiMiikjk okNiilclhiMiikjkojFiMlclhiMiik jkokNiilclhiMiikjkojFjbiY-Z-Z- Z-R<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#running-from-your-past\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Running From Your Past)dododo dododododododododododododododo dlav-gav-gat-gau-ecBcBaC-gaC-g aD-gaJ-gcX-ccY-ccY-ccz-ccj-gcj -fcH-acB-aaH-gaH-ecC-aaJ-gaJ-c cBcBcBcDby-bcBdf-adf-adf-acB-a df-adf-adf-acC-adf-ncz-ccF-aat -gau-ccBcBcBcDaa-gaa-ccD-acC-a ag-gag-ccBcBcBcDdg-Z-Z-Z-R,eq- ibw-gbibzbBcWcqbgbibycqbzbBcWc qbgbibydcbzbBcWcqbgbibycqbzbBc WcqbgbihJ-aby-acWckbf-abyckby- acWckbf-aebcWby-acWckbf-abyckb y-acWckbf-aebdpdl-gja-gdldj-ab rczcx-aaFdldj-abrdXdV-acw-acz- abD-acWckbk-abyckbD-acWckbk-ae bcWbE-acWckbl-abyckbE-acWckbl- aebdpcWdIebeueo-adV-aeo-afa-ae o-adV-aeo-afa-aeq-jkx-gdg-abzb BcWcqbgbibycqbzbBcWcqbgbipm-ab D-acWckbk-abyckbD-acWckbk-aebc WbEbGcWckblbnbyckbEbGcWckblbne bdpdl-Z-Z-Z-R,cX-iaZ-gaOcX-adX dxck-acKdxcX-adXdxck-acKdXcX-a dXdxck-acKdxcX-adXdxck-aekdXcN -adNdncacacAdncN-adNdncacaeAdN cN-adNdncacacAdncN-adNdncacaeA eahphh-agY-acIcAdnhphh-agY-acI cNcacUhpchcAhh-acUdvcUhpchcAgG -acHdn-aeF-acN-adNdncacacAdncN -adNdncacaeAdNcN-adNdncacacAdn cN-adNdncacaeAeadNeneAeNcW-acJ -acW-adw-acW-acJ-acW-adw-acX-j cm-gcg-acX-adXdxck-acKdxcX-adX dxck-aekdXcN-adNdncacacAdncN-a dNdncacaeAdNcN-adNdncacacAdncN -adNdncacaeAeadX-Z-Z-Z-R,oM-al fkOkkilldkPkmpailkNkjkNiiiMiPi M-alclfiMiikjkmkNiilclfiMiikjk mkNiMlclfiMiikjkmkNiilclfiMiik jkmjbiMlclhiMiikjkokNiilclhiMi ikjkojFiMlclhiMiikjkokNiilclhi MiikjkojFjbiY-gkx-giYiN-biuij- biYiN-bjRjG-ajI-alg-alclhiMiik jkokNiilclhiMiikjkojFiMlclhiMi ikjkokNiilclhiMiikjkojFjbiMjqj FjUoRoooQopoApaoPogoqoGoooQpgp hoF-aoM-alfkOkkilldkPkmpailkNk jkNiiiMiPiM-aiTiMlclfiMiikjkmk NiilclfiMiikjkmjbiMlclhiMiikjk okNiilclhiMiikjkojFiMlclhiMiik jkokNiilclhiMiikjkojFjbiY-Z-Z- Z-R\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"fate-of-the-rodents\">\n  <h3><a class=\"anchor\" href=\"#fate-of-the-rodents\" title=\"link to section\">#<\/a>8. Fate Of The Rodents<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: ishaq<\/li>\n      <li>Other<\/li>\n      <li>Rating: 9.00 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222031539&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=6729&amp;Itemid=60\">69 ratings, 73 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Fate Of The Rodents)-xdo-adp- adh-adf-ado-adp-adh-adf-ado-ad p-adh-adf-adocZdpcYdhcZdfcYdoc ZdpcYdhcZdfcYav-gav-gav-gav-ga v-gav-gav-gav-gav-gav-hdo-cdp- cdh-cdf-Z-Z-Z-Z-Z-v,-pao-acR-a dk-afu-aao-acR-adk-afu-aao-acR jRdk-afujnao-acRjRdk-afujnao-a cRjOdk-afujkao-acRjOdk-afujkak kccNjNdgjyfqjjakkccNjNdgjyfqjj aijUcMjFdgjyfmjjaijUcMjFdgjyfm jjafjVcLjFdjjwfnjiafjVcLjFdjjw fnjiaejZcHjKdajvfkjgaejZcHjKda jvfkjgafkacIjLdbjwfljhafkacIjL dbjwfljh!!ao-ccR-ajR-adk-cfu-a jn-Z-Z-Z-Z-Z-t,-haj-abW-acj-ad J-aaj-abW-acj-adJ-aaj-abW-acj- adJ-aajdkbWcXcjdkdJdKajdkbWcXc jdkdJdKajdkbWcXcjdkdJdKajdkbWc XcjdkdJdKajdkbWcXcjdkdJdKajdkb WcXcjdkdJdKajdkbWcXcjdkdJdKajd kbWcXcjdkdJdKajdkbWcXcjdkdJdKa jdkbWcXcjdkdJdKajdkbWcXcjdkdJd KajdkbWcXcjdkdJdKajdkbWcXcjdkd JdKajdkbWcXcjdkdJdK-aaj-adk-ab W-acX-acj-adk-adJ-adK-Z-Z-Z-Z- Z-t,an-acQ-adj-aft-aan-acQ-adj -aft-aan-acQ-adj-aft-aan-acQ-a dj-aft-aankgcQ-adjjCft-aankgcQ -adjjCft-aankdcQ-adjjzft-aankd cQ-adjjzft-aankgcQjRdjjCftjnan kgcQjRdjjCftjnankgcQjRdjjCftjn ankgcQjRdjjCftjnankgcQjRdjjCft jnankgcQjRdjjCftjnankgcQjRdjjC ftjnankgcQjRdjjCftjnankgcQjRdj jCftjnankgcQjRdjjCftjn-aan-akg -acQ-cdj-ajC-aft-Z-Z-Z-Z-Z-v<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#fate-of-the-rodents\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Fate Of The Rodents)-xdo-adp- adh-adf-ado-adp-adh-adf-ado-ad p-adh-adf-adocZdpcYdhcZdfcYdoc ZdpcYdhcZdfcYav-gav-gav-gav-ga v-gav-gav-gav-gav-gav-hdo-cdp- cdh-cdf-Z-Z-Z-Z-Z-v,-pao-acR-a dk-afu-aao-acR-adk-afu-aao-acR jRdk-afujnao-acRjRdk-afujnao-a cRjOdk-afujkao-acRjOdk-afujkak kccNjNdgjyfqjjakkccNjNdgjyfqjj aijUcMjFdgjyfmjjaijUcMjFdgjyfm jjafjVcLjFdjjwfnjiafjVcLjFdjjw fnjiaejZcHjKdajvfkjgaejZcHjKda jvfkjgafkacIjLdbjwfljhafkacIjL dbjwfljh!!ao-ccR-ajR-adk-cfu-a jn-Z-Z-Z-Z-Z-t,-haj-abW-acj-ad J-aaj-abW-acj-adJ-aaj-abW-acj- adJ-aajdkbWcXcjdkdJdKajdkbWcXc jdkdJdKajdkbWcXcjdkdJdKajdkbWc XcjdkdJdKajdkbWcXcjdkdJdKajdkb WcXcjdkdJdKajdkbWcXcjdkdJdKajd kbWcXcjdkdJdKajdkbWcXcjdkdJdKa jdkbWcXcjdkdJdKajdkbWcXcjdkdJd KajdkbWcXcjdkdJdKajdkbWcXcjdkd JdKajdkbWcXcjdkdJdK-aaj-adk-ab W-acX-acj-adk-adJ-adK-Z-Z-Z-Z- Z-t,an-acQ-adj-aft-aan-acQ-adj -aft-aan-acQ-adj-aft-aan-acQ-a dj-aft-aankgcQ-adjjCft-aankgcQ -adjjCft-aankdcQ-adjjzft-aankd cQ-adjjzft-aankgcQjRdjjCftjnan kgcQjRdjjCftjnankgcQjRdjjCftjn ankgcQjRdjjCftjnankgcQjRdjjCft jnankgcQjRdjjCftjnankgcQjRdjjC ftjnankgcQjRdjjCftjnankgcQjRdj jCftjnankgcQjRdjjCftjn-aan-akg -acQ-cdj-ajC-aft-Z-Z-Z-Z-Z-v\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"face-of-the-revolution\">\n  <h3><a class=\"anchor\" href=\"#face-of-the-revolution\" title=\"link to section\">#<\/a>9. Face of the Revolution<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Cyros Lugoth<\/li>\n      <li>Hard Rock<\/li>\n      <li>Rating: 9.82 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222031741&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=2618&amp;Itemid=60\">67 ratings, 69 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Face of the Revolution)-wcZcK -acMcK-acMcK-acMcK-acFax-bax-a cDaz-baA-acBax-bax-bax-bax-acD ad-bad-bad-bcC-acBag-bagae-aag -bagae-aag-bagae-aag-bagcE-aax -bax-bax-bax-acDax-acDaA-baB-b axcD-abt-bbt-bbt-acBbx-bbt-bbt -bbv-ccE-aby-bby-bby-bby-abyby -bby-bby-bcBcE-aax-bax-bax-bax -acDax-bax-bax-bax-acDcl-bcj-b cl-bbk-bcl-bcj-bcl-acFdf-aczax -bax-bax-bax-baz-baz-baz-baB-a cDae-bae-bag-ccB-acQ-bcQ-bcQ-b cQ-bcQ-bcQ-bcQ-bcQcD-adf-bdf-a dfdf-adjdndu-adf-acZdf-acZdf-a cZcJ-acAby-bby-acBby-bbycC-abv -bbv-bcB-acz-cag-bagae-aag-bag ae-aag-bagae-aag-bagcE-abI-bbI -bbI-bbI-bbI-bbI-bbI-bbI-bbj-b bj-bbj-bbj-bbj-bbj-bbj-bdf-wdu -v,bc-bch-baq-bcT-bbc-bch-baq- bcT-bbb-aaXcg-accap-aalcS-acOa M-bbR-baa-bcD-baN-aabaN-aabbS- bbS-abzaN-aabaN-abScE-bdt-adpb YbX-acKbE-aaTag-aaTbX-abYbX-ac KbE-aaTag-aaTaS-aaM-bbR-baa-bc D-baM-bbR-baa-bcD-baTaS-abYbX- aahag-acKcJ-aaTaS-abYbX-aahag- acKcJ-aaTaS-abYbX-aahag-acKcJ- aaTaS-abYbX-aahag-acKcJ-aaM-bb R-baa-bcD-baM-bbR-baa-bcD-baN- bab-baN-cbgaN-cbz-bbg-baN-baN- aabaN-aabaN-aabaN-aabaN-aabaN- aabaN-aabaN-aabaM-aaaaM-abffg- aeufg-aeuaM-bbR-baa-bcD-baM-bb R-baa-bcD-bbb-bcg-bap-bcT-bbb- aaXcg-accap-aeFcS-baTaS-abYbX- aahag-acKcJ-aaTaS-abYbX-aeB-bc S-bbYbX-acKbE-aaTag-aaTbX-abYb X-acKbE-aaTag-aaTaS-afs-afreG- aemen-adTdB-aeFfs-afreG-aemen- aemdB-aeFdE-bcS-bcg-bbN-bdE-bc S-bcg-bbN-bbc-bch-baq-bcT-bbc- bch-baq-bcT-v,-laK-bbx-bak-bbX -baI-aaHbv-abuai-aahbV-abUaI-a aHbv-abuai-abUbV-aahaI-aahaI-a ahbv-aahaI-abhaI-aahaI-abubV-a bUcv-abhda-bdAcN-adAda-adAen-a da-bdAcN-adAda-adA-baI-aaHbv-a buai-aahbV-abUaI-aaHbv-abuai-a ahbV-abUaI-aaHbv-abuai-aahbV-a bUaI-aaHbv-abuai-aahbV-abUaI-a aHbv-abuai-aahbV-abUaI-aaHbv-a buai-aahbV-abUaI-aaHbv-abuai-a ahbV-abUaI-aaHbv-abuai-aahbV-a bUaK-eaK-eaK-bbk-baX-baK-baI-a ahaI-aahaI-aahaI-aaUaI-aahaI-a aUaI-aahaI-aaUaI-aahaI-aaUdI-a dhdI-adUaI-aaHbv-abuai-aahbV-a bUaI-aaHbv-abuai-aahbV-abUaI-a aHbv-abuai-aahbV-abUaI-aaHbv-a buai-aahbV-abUaI-aaHbv-abuai-a ahbV-abUaI-aaHbv-abuai-aahdi-a dhda-bdAcN-adAda-adAen-ada-bdA cN-adAda-adA-bdA-bda-acN-bcAcn -adadA-bda-acN-ccn-adacv-acubV -abUbv-abubi-abhcv-acubV-abUbv -abubi-abhaI-aaHbv-abuai-aahbV -abUaI-aaHbv-abuai-aahbW-v,bc- bch-baq-bcT-bbc-bch-baq-bcT-bi K-bjD-big-bkh-biK-bjD-bnj-bnj- ahWiJ-kaN-aabaN-abScE-bdt-adpb YbX-acKbE-aaTag-aaTbX-abYbX-ac KbE-aaTag-aaT-biy-aiAiy-aiAnj- bhU-ahWiy-ajtjrhUiAnj-bjVjrjXj CjniJjCjniJjCjnifjCkgiJixjbjqi xjbjq-bhTkg-bjCjniJjCjniJjCjni fjCkgiJixjbjqixjbjq-bhTjUjqjbn y-akgjchUjrnj-bnk-ajeny-akg-aj Ckgnj-bnk-ajXjC-akgjC-akgjC-ak giJiYiJjC-akgjn-aifiY-ajCiJ-na M-aaaaM-abfaM-aaaaM-abfiA-ahUi A-aiNiA-ahUiA-aiNiyhUiAiyjcjtn j-bhU-ahWiy-ajtjrhUiAnj-bjc-aj XjCjniJjCjniJjCjnifiJ-bixjbjqi xjbjq-bhTkg-bjCjniJjCjnififjni JiJlokKkyhTixkyhTjbjC-ajnjq-aj tjrjt-ajVje-aiyhW-aiyjt-ajrjt- ajVje-aiyhW-aiyiA-aiG-aiFic-al koW-akVkH-aibnC-bkajZ-ajhjg-aj hjg-akK-bjV-bjV-bjcje-ajc-biy- biy-bif-bbc-bch-baq-bcT-bbc-bc h-baq-bcT-v<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#face-of-the-revolution\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Face of the Revolution)-wcZcK -acMcK-acMcK-acMcK-acFax-bax-a cDaz-baA-acBax-bax-bax-bax-acD ad-bad-bad-bcC-acBag-bagae-aag -bagae-aag-bagae-aag-bagcE-aax -bax-bax-bax-acDax-acDaA-baB-b axcD-abt-bbt-bbt-acBbx-bbt-bbt -bbv-ccE-aby-bby-bby-bby-abyby -bby-bby-bcBcE-aax-bax-bax-bax -acDax-bax-bax-bax-acDcl-bcj-b cl-bbk-bcl-bcj-bcl-acFdf-aczax -bax-bax-bax-baz-baz-baz-baB-a cDae-bae-bag-ccB-acQ-bcQ-bcQ-b cQ-bcQ-bcQ-bcQ-bcQcD-adf-bdf-a dfdf-adjdndu-adf-acZdf-acZdf-a cZcJ-acAby-bby-acBby-bbycC-abv -bbv-bcB-acz-cag-bagae-aag-bag ae-aag-bagae-aag-bagcE-abI-bbI -bbI-bbI-bbI-bbI-bbI-bbI-bbj-b bj-bbj-bbj-bbj-bbj-bbj-bdf-wdu -v,bc-bch-baq-bcT-bbc-bch-baq- bcT-bbb-aaXcg-accap-aalcS-acOa M-bbR-baa-bcD-baN-aabaN-aabbS- bbS-abzaN-aabaN-abScE-bdt-adpb YbX-acKbE-aaTag-aaTbX-abYbX-ac KbE-aaTag-aaTaS-aaM-bbR-baa-bc D-baM-bbR-baa-bcD-baTaS-abYbX- aahag-acKcJ-aaTaS-abYbX-aahag- acKcJ-aaTaS-abYbX-aahag-acKcJ- aaTaS-abYbX-aahag-acKcJ-aaM-bb R-baa-bcD-baM-bbR-baa-bcD-baN- bab-baN-cbgaN-cbz-bbg-baN-baN- aabaN-aabaN-aabaN-aabaN-aabaN- aabaN-aabaN-aabaM-aaaaM-abffg- aeufg-aeuaM-bbR-baa-bcD-baM-bb R-baa-bcD-bbb-bcg-bap-bcT-bbb- aaXcg-accap-aeFcS-baTaS-abYbX- aahag-acKcJ-aaTaS-abYbX-aeB-bc S-bbYbX-acKbE-aaTag-aaTbX-abYb X-acKbE-aaTag-aaTaS-afs-afreG- aemen-adTdB-aeFfs-afreG-aemen- aemdB-aeFdE-bcS-bcg-bbN-bdE-bc S-bcg-bbN-bbc-bch-baq-bcT-bbc- bch-baq-bcT-v,-laK-bbx-bak-bbX -baI-aaHbv-abuai-aahbV-abUaI-a aHbv-abuai-abUbV-aahaI-aahaI-a ahbv-aahaI-abhaI-aahaI-abubV-a bUcv-abhda-bdAcN-adAda-adAen-a da-bdAcN-adAda-adA-baI-aaHbv-a buai-aahbV-abUaI-aaHbv-abuai-a ahbV-abUaI-aaHbv-abuai-aahbV-a bUaI-aaHbv-abuai-aahbV-abUaI-a aHbv-abuai-aahbV-abUaI-aaHbv-a buai-aahbV-abUaI-aaHbv-abuai-a ahbV-abUaI-aaHbv-abuai-aahbV-a bUaK-eaK-eaK-bbk-baX-baK-baI-a ahaI-aahaI-aahaI-aaUaI-aahaI-a aUaI-aahaI-aaUaI-aahaI-aaUdI-a dhdI-adUaI-aaHbv-abuai-aahbV-a bUaI-aaHbv-abuai-aahbV-abUaI-a aHbv-abuai-aahbV-abUaI-aaHbv-a buai-aahbV-abUaI-aaHbv-abuai-a ahbV-abUaI-aaHbv-abuai-aahdi-a dhda-bdAcN-adAda-adAen-ada-bdA cN-adAda-adA-bdA-bda-acN-bcAcn -adadA-bda-acN-ccn-adacv-acubV -abUbv-abubi-abhcv-acubV-abUbv -abubi-abhaI-aaHbv-abuai-aahbV -abUaI-aaHbv-abuai-aahbW-v,bc- bch-baq-bcT-bbc-bch-baq-bcT-bi K-bjD-big-bkh-biK-bjD-bnj-bnj- ahWiJ-kaN-aabaN-abScE-bdt-adpb YbX-acKbE-aaTag-aaTbX-abYbX-ac KbE-aaTag-aaT-biy-aiAiy-aiAnj- bhU-ahWiy-ajtjrhUiAnj-bjVjrjXj CjniJjCjniJjCjnifjCkgiJixjbjqi xjbjq-bhTkg-bjCjniJjCjniJjCjni fjCkgiJixjbjqixjbjq-bhTjUjqjbn y-akgjchUjrnj-bnk-ajeny-akg-aj Ckgnj-bnk-ajXjC-akgjC-akgjC-ak giJiYiJjC-akgjn-aifiY-ajCiJ-na M-aaaaM-abfaM-aaaaM-abfiA-ahUi A-aiNiA-ahUiA-aiNiyhUiAiyjcjtn j-bhU-ahWiy-ajtjrhUiAnj-bjc-aj XjCjniJjCjniJjCjnifiJ-bixjbjqi xjbjq-bhTkg-bjCjniJjCjnififjni JiJlokKkyhTixkyhTjbjC-ajnjq-aj tjrjt-ajVje-aiyhW-aiyjt-ajrjt- ajVje-aiyhW-aiyiA-aiG-aiFic-al koW-akVkH-aibnC-bkajZ-ajhjg-aj hjg-akK-bjV-bjV-bjcje-ajc-biy- biy-bif-bbc-bch-baq-bcT-bbc-bc h-baq-bcT-v\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"when-all-hope-is-lost\">\n  <h3><a class=\"anchor\" href=\"#when-all-hope-is-lost\" title=\"link to section\">#<\/a>10. When All Hope Is Lost (Eat Cupcakes)<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: eXInferis<\/li>\n      <li>Punk<\/li>\n      <li>Rating: 9.95 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222031338&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=8239&amp;Itemid=60\">66 ratings, 73 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(When All Hope Is Lost)-pda-bd bda-adbdcdgdgdg-acz-cababab-ab A-abDcBababab-abE-bcEababab-ab y-acC-abAbAbA-aababagcBbF-wbF- gbG-ecIczcF-acF-acF-acFcEcF-ac F-acF-acFcBaa-gabababcBbA-bdhb J-gbR-gdg-ccIbF-fbtbF-fdg-Bdu- ccE-adh-TcPbG-gbG-gbG-cbG-cbG- gbG-cbG-gbG-bdgdgda-bdgda-adgd g-fdgdg-bdgdg-Z-Z-l,ifiJiY-akv -akZ-aifiJiYkvkgiYjCiYiYjCkg-a kg-ajC-aiYjCkgiYbg-adJkNiMjqjU iMjUiMjqiMiMjqjUkNjUkNjq-aiMjq hT-aiM-aix-aiMjqhTkNjUkNjqiMeJ -bpm-apq-bevfhcX-aiN-afhdJevfh cX-aiP-adJdXhUiyiN-aiNjV-ajr-a iNkk-ajVkkjriMeu!!cW!!bf!!fgjU eu!!cW!!bf!!fgbfeufgiM-abl-adI -aeufgiM-aiM-aixdjjU-cjq-aiM-a jU-ajq-aiM-afg-aeJ-ceFeJiMixiM -cixhTiMixiM-ckg-paq-akw-aiZ-a jD-akh-aiZ-akh-ajD-ccW-acDbRcW -acDdIeu-ceu-bdIcW-cdI-ceu-ceu -bdIcW-cdI-ceu-ceu-bdIcW-acDbR cW-acDdIeu-ceu-bdIcW-cdI-ceu-c eu-bdIcW-cdI-ceu-ceuaaeuaadl-c dX-cap-fdXdl-beJfv-aifiJiY-Z-Z -h,-gdZ-ghFdkdKck-adX-acK-adkd Kck-aaX-acK-adkcKck-adN-acA-ad kcKck-adNaNcA-adkdKck-adN-adA- adkcKck-adNcAdAdXak-fhF!!-oagc Gcg-aaT-adTcGdgdGdT-aaT-acGcAd a!!ca!!dN!!dAcAda!!ca!!dN!!dAd NdacAca-adN-acA-adacAca-adN-ad AcjeN-cen-aaN-aeN-aen-adN-aaA- aak-abXeNahak-cck-cak-cck-b!!- Hdj-Uca-aeNenca-aeNcAaada-aaad a-aaaaaca-ccA-cdaaadaaadaaadaa aca-ccA-caa-caa-cck-ccK-cdk-fc Kck-bakaK-cak-Z-Z-h,iYjCkg-aiY -ajC-aiYjCkgiYiY-aiJ-aifkZkviY iY-aiJ-aifkZkv-aiYiYix-aeudIcW -aiM-akN-aeudIcW-aiMiMix-aeufg iMkNjUkNjqiMeufgcWdIiM-aixixif -cpq-chUfgkkcWbgjUiyjChUfgiN-a jXiMjriJhUkOkk-aiN-akO-ahUiyiN -aiN-akOdIhTkgkjkgiMkgjCkNhTkg kjkgiMkgixiMiMjqjU-aiRiMjUjqiM jqjUiMjUiMjqktiM-ahT-aix-akN-a iM-akj-abf-aix-aif-cibif-ccWiM jqiMeyev-bnB-ceK-adm-abv-adY-a eK-adm-abv-adY-aeK-adm-abv-adY -aeK-adm-abv-adY-apm-ace-eiZ-b iMixhT-aiMjqixiM-ajUiMjq-aiMix nV-cnV-akNmimimi-geu-bne-ckj-a jUjqkj-ajUkNhTiMixhT-aiMjqixiM -ajUiMjq-aiMixnV-cnV-cmimi-gmf -bhT-ajUiM-bixhTix-ahTkNhT-ajU hTjqiMixkNkv-bifkZ-bkZif-Z-Z-h<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#when-all-hope-is-lost\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(When All Hope Is Lost)-pda-bd bda-adbdcdgdgdg-acz-cababab-ab A-abDcBababab-abE-bcEababab-ab y-acC-abAbAbA-aababagcBbF-wbF- gbG-ecIczcF-acF-acF-acFcEcF-ac F-acF-acFcBaa-gabababcBbA-bdhb J-gbR-gdg-ccIbF-fbtbF-fdg-Bdu- ccE-adh-TcPbG-gbG-gbG-cbG-cbG- gbG-cbG-gbG-bdgdgda-bdgda-adgd g-fdgdg-bdgdg-Z-Z-l,ifiJiY-akv -akZ-aifiJiYkvkgiYjCiYiYjCkg-a kg-ajC-aiYjCkgiYbg-adJkNiMjqjU iMjUiMjqiMiMjqjUkNjUkNjq-aiMjq hT-aiM-aix-aiMjqhTkNjUkNjqiMeJ -bpm-apq-bevfhcX-aiN-afhdJevfh cX-aiP-adJdXhUiyiN-aiNjV-ajr-a iNkk-ajVkkjriMeu!!cW!!bf!!fgjU eu!!cW!!bf!!fgbfeufgiM-abl-adI -aeufgiM-aiM-aixdjjU-cjq-aiM-a jU-ajq-aiM-afg-aeJ-ceFeJiMixiM -cixhTiMixiM-ckg-paq-akw-aiZ-a jD-akh-aiZ-akh-ajD-ccW-acDbRcW -acDdIeu-ceu-bdIcW-cdI-ceu-ceu -bdIcW-cdI-ceu-ceu-bdIcW-acDbR cW-acDdIeu-ceu-bdIcW-cdI-ceu-c eu-bdIcW-cdI-ceu-ceuaaeuaadl-c dX-cap-fdXdl-beJfv-aifiJiY-Z-Z -h,-gdZ-ghFdkdKck-adX-acK-adkd Kck-aaX-acK-adkcKck-adN-acA-ad kcKck-adNaNcA-adkdKck-adN-adA- adkcKck-adNcAdAdXak-fhF!!-oagc Gcg-aaT-adTcGdgdGdT-aaT-acGcAd a!!ca!!dN!!dAcAda!!ca!!dN!!dAd NdacAca-adN-acA-adacAca-adN-ad AcjeN-cen-aaN-aeN-aen-adN-aaA- aak-abXeNahak-cck-cak-cck-b!!- Hdj-Uca-aeNenca-aeNcAaada-aaad a-aaaaaca-ccA-cdaaadaaadaaadaa aca-ccA-caa-caa-cck-ccK-cdk-fc Kck-bakaK-cak-Z-Z-h,iYjCkg-aiY -ajC-aiYjCkgiYiY-aiJ-aifkZkviY iY-aiJ-aifkZkv-aiYiYix-aeudIcW -aiM-akN-aeudIcW-aiMiMix-aeufg iMkNjUkNjqiMeufgcWdIiM-aixixif -cpq-chUfgkkcWbgjUiyjChUfgiN-a jXiMjriJhUkOkk-aiN-akO-ahUiyiN -aiN-akOdIhTkgkjkgiMkgjCkNhTkg kjkgiMkgixiMiMjqjU-aiRiMjUjqiM jqjUiMjUiMjqktiM-ahT-aix-akN-a iM-akj-abf-aix-aif-cibif-ccWiM jqiMeyev-bnB-ceK-adm-abv-adY-a eK-adm-abv-adY-aeK-adm-abv-adY -aeK-adm-abv-adY-apm-ace-eiZ-b iMixhT-aiMjqixiM-ajUiMjq-aiMix nV-cnV-akNmimimi-geu-bne-ckj-a jUjqkj-ajUkNhTiMixhT-aiMjqixiM -ajUiMjq-aiMixnV-cnV-cmimi-gmf -bhT-ajUiM-bixhTix-ahTkNhT-ajU hTjqiMixkNkv-bifkZ-bkZif-Z-Z-h\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n"},{"title":"Punk-o-Matic.net Top Rated","published":"2024-03-20T00:00:00+00:00","updated":"2024-03-20T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/punkomatic\/pom-net-top-rated\/"}},"id":"https:\/\/iliazeus.lol\/punkomatic\/pom-net-top-rated\/","content":"<p>These were salvaged with the help of <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/web.archive.org\/web\/20130202170442\/http:\/\/www.punk-o-matic.net\/index.php?option=com_usercontents&amp;task=displayallcontents&amp;mode=toprated&amp;type=0&amp;Itemid=60\">Internet Archive<\/a>.<\/p>\n<hgroup class=\"punkomatic-song\" id=\"entwined-thoughts\">\n  <h3><a class=\"anchor\" href=\"#entwined-thoughts\" title=\"link to section\">#<\/a>1. Entwined Thoughts - BracketMadnessEntry3<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Plug and Play<\/li>\n      <li>Metal<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li>34 ratings, 37 comments<\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(fghjkl)-ncO-acO-ccO-ccK-ccK-c cK-ccK-ccK-ccK-ccK-ccL-acD-acJ -acYdsdg-ncDdg-bcDascEascCam-a cE-aas-acD-adg-ecD-abt-cbt-bcE bt-cbt-acC-abt-fcDbt-acDcCcF-a cJ-adf-dbLdg-aambPbIaGbLcDdg-g da-cda-ccK-ccK-ccK-ccK-acKcBby -adh-abycCdh-aby-adh-abycCdg-g dqdqdqdqdqdqdqdqcW-acV-acU-acB -abt-gbt-ecF-aat-acD-adg-ccR-c cR-ccR-ccR-ccQ-ccQ-ccQ-acD-adg -fcDbG-gbG-ecD-abL-bambL-bambL -basbL-bdhby-cby-bcEby-aas-aby -acE-aam-adh-Z-Z-i,jD-akh-ajD- ajo-aiK-ajD-a!!-cbd-gnzmClYjcm o-cnzmClYjcmo-cma-anz-bjcjrnzc MlY-amo-bje-aiJ-caN-caRbkaRafb b-caRbkbWbkbbgL-abbdX-aeJ-agN- agWgSbb-cgO-cgO-agOgygO-cdMdJ- baegz-agbaR-aaU-ajbml-ajblAjxj bkbhTnb-ahTkK-dgybb-dgybb-bgyf Ybubb-jbc-cgNbb-bgMbb-bgMbb-bg MbbgMaMbfiEiMiJ-aiEiMiJ-aiEiMi J-aiEiMiJ-gaO-caO-cdJ-cez-cfg- alAjbjq-alS-ahTmh-alTky-akF-ad N-bdSdE-aifkZkB-ckQ-bhWkB-ckQ- bhWiA-bhWiA-aiPjtjt-ajehWiJ-cb c-baXaRgIaR-aaRgIaR-adNgidN-ad u-bezaM-cgJ-cdI-bgiducIbWbkaMg L-aaMdX-aeJ-agN-agWgSbb-caU-af t-Z-Z-i,aK-bbxaK-bakcK-bbXcx-c gp-bfZgp-aeseSgp-bfZgp-aeseRgp -bfZgp-aesfZcC-adc-agp-agpfZcF -acIeTco-acnhFaKdXdK-aaK-cdDdQ dDddaA-cdDdQeqhBaDaA-bcDcGdidQ aC-agxguaC-agnguaK-aaBfZaK-agp fZdF-aaDaGcCcF-acGdc-beQaC-aaB eXaCaD-bcCcD-bac-agoexaK-bfZaK fZaKfZfzgJaKfZaKfZaKfZbXgIaK-a gkfUaCfCgkfUaAfCgkfUaCfCgkfUgk fCaCfUaCgc-afCaCfUaCfCaCfUaCfC aDadgj-aaDfUgn-aaDadgj-aaDfUaK -adkdXdK-aaK-aaK-caK-ccK-cadgo -aevaE-agoefcE-bdFad-bexaD-adg etcD-bcqcx-cgp-bfCgp-afwgQgp-b fCgp-afwgQgp-cgp-bgacC-acq-aaK -caK-bdOaDgjaD-aaDgjaD-acDfFcC -acp-abPaPaF-aaEaHgk-ccF-acEfF cnbNbnaWaDaF-bcDcFafdQgn-agxgu gn-agnguaE-aaJ-Z-Z-i,iK-aig-ai K-aig-ala-aig-adF-cgO-agOgygO- agOgygO-agOgygO-agOgygO-agOgyg O-agOgydM-aaegygO-agOgydM-adMe Edu-cbb-cmooviynliy-cmoovlYiNi y-bgL-abb-agL-acgfYbubb-cgN-ag WgSbb-fmiixky-amiixkN-amhjb-aj qjb-aix-amiixky-amiixkN-amhjb- ajqjbiJ-bgybb-bgyfYbubb-bgybb- cfv-dbc-baNgbaNgtaNgbaNgtaNgba NgtaNgB-agbaNgtaNgbaNgtaNgbaRg uaZ-aaRguaZ-aaRguaZ-aaRgubb-fm g-anHkymgky-bnHhT-bmljb-bmiixk y-amiixkN-amljb-ajqjb-aix-anbk NhTmhjqjn-cgO-bgbgO-afVhpgO-bg bgO-afVhpgO-cgO-bgzdJ-adt-afv- aiz-aiO-aiz-aixkynHky-cnb-akyn Hky-chTixjqiMjqix-cixjqiMjqix- bgL-abb-agL-acgfYbubb-cgN-agWg Sbb-aaZ-Z-Z-i<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#entwined-thoughts\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(fghjkl)-ncO-acO-ccO-ccK-ccK-c cK-ccK-ccK-ccK-ccK-ccL-acD-acJ -acYdsdg-ncDdg-bcDascEascCam-a cE-aas-acD-adg-ecD-abt-cbt-bcE bt-cbt-acC-abt-fcDbt-acDcCcF-a cJ-adf-dbLdg-aambPbIaGbLcDdg-g da-cda-ccK-ccK-ccK-ccK-acKcBby -adh-abycCdh-aby-adh-abycCdg-g dqdqdqdqdqdqdqdqcW-acV-acU-acB -abt-gbt-ecF-aat-acD-adg-ccR-c cR-ccR-ccR-ccQ-ccQ-ccQ-acD-adg -fcDbG-gbG-ecD-abL-bambL-bambL -basbL-bdhby-cby-bcEby-aas-aby -acE-aam-adh-Z-Z-i,jD-akh-ajD- ajo-aiK-ajD-a!!-cbd-gnzmClYjcm o-cnzmClYjcmo-cma-anz-bjcjrnzc MlY-amo-bje-aiJ-caN-caRbkaRafb b-caRbkbWbkbbgL-abbdX-aeJ-agN- agWgSbb-cgO-cgO-agOgygO-cdMdJ- baegz-agbaR-aaU-ajbml-ajblAjxj bkbhTnb-ahTkK-dgybb-dgybb-bgyf Ybubb-jbc-cgNbb-bgMbb-bgMbb-bg MbbgMaMbfiEiMiJ-aiEiMiJ-aiEiMi J-aiEiMiJ-gaO-caO-cdJ-cez-cfg- alAjbjq-alS-ahTmh-alTky-akF-ad N-bdSdE-aifkZkB-ckQ-bhWkB-ckQ- bhWiA-bhWiA-aiPjtjt-ajehWiJ-cb c-baXaRgIaR-aaRgIaR-adNgidN-ad u-bezaM-cgJ-cdI-bgiducIbWbkaMg L-aaMdX-aeJ-agN-agWgSbb-caU-af t-Z-Z-i,aK-bbxaK-bakcK-bbXcx-c gp-bfZgp-aeseSgp-bfZgp-aeseRgp -bfZgp-aesfZcC-adc-agp-agpfZcF -acIeTco-acnhFaKdXdK-aaK-cdDdQ dDddaA-cdDdQeqhBaDaA-bcDcGdidQ aC-agxguaC-agnguaK-aaBfZaK-agp fZdF-aaDaGcCcF-acGdc-beQaC-aaB eXaCaD-bcCcD-bac-agoexaK-bfZaK fZaKfZfzgJaKfZaKfZaKfZbXgIaK-a gkfUaCfCgkfUaAfCgkfUaCfCgkfUgk fCaCfUaCgc-afCaCfUaCfCaCfUaCfC aDadgj-aaDfUgn-aaDadgj-aaDfUaK -adkdXdK-aaK-aaK-caK-ccK-cadgo -aevaE-agoefcE-bdFad-bexaD-adg etcD-bcqcx-cgp-bfCgp-afwgQgp-b fCgp-afwgQgp-cgp-bgacC-acq-aaK -caK-bdOaDgjaD-aaDgjaD-acDfFcC -acp-abPaPaF-aaEaHgk-ccF-acEfF cnbNbnaWaDaF-bcDcFafdQgn-agxgu gn-agnguaE-aaJ-Z-Z-i,iK-aig-ai K-aig-ala-aig-adF-cgO-agOgygO- agOgygO-agOgygO-agOgygO-agOgyg O-agOgydM-aaegygO-agOgydM-adMe Edu-cbb-cmooviynliy-cmoovlYiNi y-bgL-abb-agL-acgfYbubb-cgN-ag WgSbb-fmiixky-amiixkN-amhjb-aj qjb-aix-amiixky-amiixkN-amhjb- ajqjbiJ-bgybb-bgyfYbubb-bgybb- cfv-dbc-baNgbaNgtaNgbaNgtaNgba NgtaNgB-agbaNgtaNgbaNgtaNgbaRg uaZ-aaRguaZ-aaRguaZ-aaRgubb-fm g-anHkymgky-bnHhT-bmljb-bmiixk y-amiixkN-amljb-ajqjb-aix-anbk NhTmhjqjn-cgO-bgbgO-afVhpgO-bg bgO-afVhpgO-cgO-bgzdJ-adt-afv- aiz-aiO-aiz-aixkynHky-cnb-akyn Hky-chTixjqiMjqix-cixjqiMjqix- bgL-abb-agL-acgfYbubb-cgN-agWg Sbb-aaZ-Z-Z-i\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"evening-break\">\n  <h3><a class=\"anchor\" href=\"#evening-break\" title=\"link to section\">#<\/a>2. Evening Break<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Downfall-RiD<\/li>\n      <li>Punk<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222034431&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=8608&amp;Itemid=60\">32 ratings, 35 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Evening Break)-pcT-ccT-ccT-cc T-bcFcs-gcs-gcs-gcs-ecA-aaQ-ga Q-gaQ-gaQ-ecC-aaD-gaD-ecF-abt- ecB-abF-can-acD-abz-gbF-cab-ac B-acs-fcAbN-cbP-ccw-acH-adg-Z- Z-Z-Z-Z-o,pu-clo-cif-cpu-cpu-c lo-cif-cpu-ccS-cje-chW-ciA-ccH -cje-chW-ciA-ccD-clc-chT-ccD-c cD-clc-chT-ccD-cpu-dixlcjb-bix hTlc-cjU-cjUixlcjb-bjFjUjF-ajU -alh-akEcKiD-akEjb-bixhTlc-ahT -ajU-cjF-ajb-ahT-cix-aiy-ciG-a lo-akKpuiJ-akKlopu-akKlolo-akK -epu-Z-Z-Z-Z-U,-dbk-cdk-cdK-cb X-cbk-cdk-cdK-cbP-cbc-cdc-cdC- aaC-abP-cbc-cdc-cdC-aaC-abN-cb a-cda-cdA-cbN-cba-cda-cdA-cbN- cba-cda-aaa-aaA-aaI-abP-cbc-cd a-cdC-aaA-abS-cbf-cda-cdA-cbP- cbc-cda-cdA-cdA-aaI-abX-cbk-cd k-cdK-gbX-Z-Z-Z-Z-U,lo-akKpuiJ -apujnjn-aiJiflo-akK-alo-akKpu iJ-apujnjn-aiJiflo-akK-apu-dix lcjb-bixhTlc-cky-alckylcixlcjb -bjFjUjF-bjUlc-akypuix-akyjb-b ixhTlc-aky-alc-akypuix-akylcmf -akylc-bky-acE-cbz-cev-ahU-aiy -afs-acH-cby-chT-ciA-aix-acK-a cJ-ali-blchT-cix-aky-alc-akypu ix-akyjb-bixhTlc-clc-aky-apu-c lo-cif-ciJ-aif-elo-Z-Z-Z-Z-U<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#evening-break\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Evening Break)-pcT-ccT-ccT-cc T-bcFcs-gcs-gcs-gcs-ecA-aaQ-ga Q-gaQ-gaQ-ecC-aaD-gaD-ecF-abt- ecB-abF-can-acD-abz-gbF-cab-ac B-acs-fcAbN-cbP-ccw-acH-adg-Z- Z-Z-Z-Z-o,pu-clo-cif-cpu-cpu-c lo-cif-cpu-ccS-cje-chW-ciA-ccH -cje-chW-ciA-ccD-clc-chT-ccD-c cD-clc-chT-ccD-cpu-dixlcjb-bix hTlc-cjU-cjUixlcjb-bjFjUjF-ajU -alh-akEcKiD-akEjb-bixhTlc-ahT -ajU-cjF-ajb-ahT-cix-aiy-ciG-a lo-akKpuiJ-akKlopu-akKlolo-akK -epu-Z-Z-Z-Z-U,-dbk-cdk-cdK-cb X-cbk-cdk-cdK-cbP-cbc-cdc-cdC- aaC-abP-cbc-cdc-cdC-aaC-abN-cb a-cda-cdA-cbN-cba-cda-cdA-cbN- cba-cda-aaa-aaA-aaI-abP-cbc-cd a-cdC-aaA-abS-cbf-cda-cdA-cbP- cbc-cda-cdA-cdA-aaI-abX-cbk-cd k-cdK-gbX-Z-Z-Z-Z-U,lo-akKpuiJ -apujnjn-aiJiflo-akK-alo-akKpu iJ-apujnjn-aiJiflo-akK-apu-dix lcjb-bixhTlc-cky-alckylcixlcjb -bjFjUjF-bjUlc-akypuix-akyjb-b ixhTlc-aky-alc-akypuix-akylcmf -akylc-bky-acE-cbz-cev-ahU-aiy -afs-acH-cby-chT-ciA-aix-acK-a cJ-ali-blchT-cix-aky-alc-akypu ix-akyjb-bixhTlc-clc-aky-apu-c lo-cif-ciJ-aif-elo-Z-Z-Z-Z-U\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"we-walk-this-earth\">\n  <h3><a class=\"anchor\" href=\"#we-walk-this-earth\" title=\"link to section\">#<\/a>3. We Walk This Earth<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Cyros Lugoth, NiceDog<\/li>\n      <li>Hard Rock<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li>31 ratings, 38 comments<\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(We Walk This Earth)-udq-adq-a dq-adq-adq-adq-adq-adqdodkdodk dodkdodgch-gch-ecBcBbG-gbG-cbL -acC-aaD-gaD-caD-bcDaU-caU-bcB ai-cai-acD-adf-cdu-cdt-fcIdn-c du-ccR-ccR-ccR-ccR-bdkcS-ccS-c cS-cbk-bcBax-gax-caq-bcBaD-gaD -caD-bcDaU-caU-bcBai-cai-acIcH aD-caJamaJasaD-cam-acB-abt-gbt -ecE-aaT-caT-caT-cbo-cbI-gbI-c bI-acG-adldrdldrdldrdldrdldrdl drdldrdlcOdl-adl-adg-Z-Z-M,aq- bnLif-bnLkZ-bnLkv-ckv-akZleiY- bnLiJ-bnLif-bnLlo-cpu-giNizhUn l-aldhUiykkklkkjrbi-aldcKnL-an jnLlelf-aiznL-bkPhW-alf-ago-cf zgPgN-ago-ccb-ahTkNmf-amfluhT- aiBnxiT-aix-ane-cap-gap-ccg-ba ldl-cdX-acS-aif-ciJ-cif-ckZ-ca nabaZabbsabgA-acebScQcEap-cana baZabbsabgv-acebScQcGae-aag-ag o-cfzgPgN-ago-ccb-ahTkNmf-amfl uhT-aiBnxiT-aix-ahTndkbmgaagwb f-ahWhVnM-anLiziOjsiTjxjUjqeA- ceAdOdcbmag-bcJezdNdadLdl-bdXe J-bmfkv-alo-aap-bnLif-bnLkZ-bn Lkv-ckv-akZleiY-bnLiJ-bnLif-bn Llo-gap-Z-Z-M,al-bhFak-ccK-cbx -cck-acKbXdjdjdjdjdjdjdjdjdjdj djdjcWcWcWcVajajajajagajagaidg didhdabTbVbUbVbtbnbubnaTaVbUbS da-bdbbN-bbObnbu-abncc-abUcOaa -afXaaaNgwgoeraa-afXaaeubucafv aa-afXaaaNgwgoeraa-afXaaeubuaN fvdk-cdk-cdk-bdkbx-bexck-bckcK -acXeXaadhaaeXendAcGbPcadhcadX cBdBcBetdagddAgddNeNendNengAeN fvac-bafaagdaAgdaNeNepdPbnenbN dAaa-aaf-aaa-afXaaaNgwgoeraa-a fXaaeubucafvaa-afXaaaNgwgoeraa -afXaachcacGcIaafWaN-aca-acA-a aafWaN-aca-acA-ada-cdacAca-aaa -bbSdacAcacAck-bcKdk-bcKbx-acX -aak-babakbXbxaXakbXbxaXbxaXaK bxckbXcKbXdkeXexdXdkeXexdXexdX dKdkdKcXbXeXcX-adK-adk-aak-Z-Z -K,eK-bnjiY-bnjiJ-bnjif-cif-ai Jizkg-bnjjC-bjsiY-bnjiJ-cif-gj VjsiNjV-aiy-bjrjsjroTnn-aizlfn k-aiOiMix-ajUiCnk-aklmFhT-aixm jhT-aixiBiM-aju-akb-ajq-ajx-ai MixhT-aixiBiM-aju-akb-ajq-ajx- aiMixif-gif-aiY-aiJ-cif-ajC-ai J-biYiY-akg-ajC-ciY-ajC-aiJ-bk Zif-gig-chU-chUcMiycMiNcMoTcMj roTiycMiN-ahW-ahT-aixiBiM-aju- akb-ajq-ajx-aiMixhT-aixiBiM-aj u-akb-ajq-ajx-aiTiBnk-cnM-anJ- ank-cnQ-blxnf-anQoeni-bmsng-an gmtpgnBnglKif-bixiY-bkNifiYiJl oif-bnjiY-bnjiJ-bnjif-cif-aiJi zkg-bnjjC-bjsiY-biOkg-gif-Z-Z- M<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#we-walk-this-earth\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(We Walk This Earth)-udq-adq-a dq-adq-adq-adq-adq-adqdodkdodk dodkdodgch-gch-ecBcBbG-gbG-cbL -acC-aaD-gaD-caD-bcDaU-caU-bcB ai-cai-acD-adf-cdu-cdt-fcIdn-c du-ccR-ccR-ccR-ccR-bdkcS-ccS-c cS-cbk-bcBax-gax-caq-bcBaD-gaD -caD-bcDaU-caU-bcBai-cai-acIcH aD-caJamaJasaD-cam-acB-abt-gbt -ecE-aaT-caT-caT-cbo-cbI-gbI-c bI-acG-adldrdldrdldrdldrdldrdl drdldrdlcOdl-adl-adg-Z-Z-M,aq- bnLif-bnLkZ-bnLkv-ckv-akZleiY- bnLiJ-bnLif-bnLlo-cpu-giNizhUn l-aldhUiykkklkkjrbi-aldcKnL-an jnLlelf-aiznL-bkPhW-alf-ago-cf zgPgN-ago-ccb-ahTkNmf-amfluhT- aiBnxiT-aix-ane-cap-gap-ccg-ba ldl-cdX-acS-aif-ciJ-cif-ckZ-ca nabaZabbsabgA-acebScQcEap-cana baZabbsabgv-acebScQcGae-aag-ag o-cfzgPgN-ago-ccb-ahTkNmf-amfl uhT-aiBnxiT-aix-ahTndkbmgaagwb f-ahWhVnM-anLiziOjsiTjxjUjqeA- ceAdOdcbmag-bcJezdNdadLdl-bdXe J-bmfkv-alo-aap-bnLif-bnLkZ-bn Lkv-ckv-akZleiY-bnLiJ-bnLif-bn Llo-gap-Z-Z-M,al-bhFak-ccK-cbx -cck-acKbXdjdjdjdjdjdjdjdjdjdj djdjcWcWcWcVajajajajagajagaidg didhdabTbVbUbVbtbnbubnaTaVbUbS da-bdbbN-bbObnbu-abncc-abUcOaa -afXaaaNgwgoeraa-afXaaeubucafv aa-afXaaaNgwgoeraa-afXaaeubuaN fvdk-cdk-cdk-bdkbx-bexck-bckcK -acXeXaadhaaeXendAcGbPcadhcadX cBdBcBetdagddAgddNeNendNengAeN fvac-bafaagdaAgdaNeNepdPbnenbN dAaa-aaf-aaa-afXaaaNgwgoeraa-a fXaaeubucafvaa-afXaaaNgwgoeraa -afXaachcacGcIaafWaN-aca-acA-a aafWaN-aca-acA-ada-cdacAca-aaa -bbSdacAcacAck-bcKdk-bcKbx-acX -aak-babakbXbxaXakbXbxaXbxaXaK bxckbXcKbXdkeXexdXdkeXexdXexdX dKdkdKcXbXeXcX-adK-adk-aak-Z-Z -K,eK-bnjiY-bnjiJ-bnjif-cif-ai Jizkg-bnjjC-bjsiY-bnjiJ-cif-gj VjsiNjV-aiy-bjrjsjroTnn-aizlfn k-aiOiMix-ajUiCnk-aklmFhT-aixm jhT-aixiBiM-aju-akb-ajq-ajx-ai MixhT-aixiBiM-aju-akb-ajq-ajx- aiMixif-gif-aiY-aiJ-cif-ajC-ai J-biYiY-akg-ajC-ciY-ajC-aiJ-bk Zif-gig-chU-chUcMiycMiNcMoTcMj roTiycMiN-ahW-ahT-aixiBiM-aju- akb-ajq-ajx-aiMixhT-aixiBiM-aj u-akb-ajq-ajx-aiTiBnk-cnM-anJ- ank-cnQ-blxnf-anQoeni-bmsng-an gmtpgnBnglKif-bixiY-bkNifiYiJl oif-bnjiY-bnjiJ-bnjif-cif-aiJi zkg-bnjjC-bjsiY-biOkg-gif-Z-Z- M\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"a-tragedy-unsung\">\n  <h3><a class=\"anchor\" href=\"#a-tragedy-unsung\" title=\"link to section\">#<\/a>4. A Tragedy Unsung<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Necromancer<\/li>\n      <li>Other<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222033907&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=1239&amp;Itemid=60\">28 ratings, 31 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(A Tragedy Unsung)-hdu-cdf-cdu -ccC-acD-acC-acD-acE-acE-abz-c cC-acD-abz-acB-abE-gbE-ecE-aaC -gaC-fcBaT-caT-caT-caT-cba-cba -cba-cba-acD-acK-ccK-ccK-ccK-c cK-ccK-ccK-ccE-acE-acB-acB-acB -acJ-abE-gbE-gbE-gbE-ccE-acJ-a bT-gbT-gbT-gbT-ccE-acE-aba-cba -cba-cba-cba-cba-cba-cba-cbT-g bT-gbT-gdf-cdu-cdt-cdu-cdt-cdu -ccN-ccK-acD-adfdfdfdfbE-ccC-a cD-abE-acE-abE-gcC-acD-abE-acE -abS-gbS-gbS-gbS-ecJ-abT-gbT-g bT-gbT-cdfdfcJ-adf-ddu-cdt-H,- ajCjnifkZ-ckK-aif-akZ-cdY-cbbb bbbbbbbbbbbbbbbbbbbbbdI-caM-cd I-aaa-aaM-cdI-caM-cdI-aaa-abb- kdY-caQ-cdM-caQ-cdM-caQ-cdM-ca Q-cdM-adX-adI-caa-caM-caM-cdI- caa-caM-caM-cbY-cah-aap-aaM-cd I-caM-cdI-aaa-aaM-cdI-caM-cdI- aap-abb-gap-gdX-gdE-epm-aaM-ca M-caa-caa-cdI-cdI-cdp-cdp-cdX- gbb-gdX-gbb-gbh-cbh-cbh-cbh-ce d-cav-cbubububueb-cbf-ceb-aat- abf-ceb-cbf-ceb-aat-abf-cbf-ca t-cat-ceb-ceb-cdI-cdI-adX-abu- gaI-geq-gdX-gbu-dkZ-cjR-H,-lcK -gaKaKaKaKaKaKaKaKaKaKaKaKcA-c aA-ccA-aaa-aaA-ccA-caA-ccA-aaa -aaK-gaK-ccK-caC-ccC-caC-ccC-c aC-ccC-caC-ccC-acK-acA-caa-caA -caA-ccA-caa-caA-caA-cbs-caf-a ak-aaA-ccA-caA-ccA-aaa-aaA-ccA -caA-ccA-aak-aaA-caA-caa-caa-c cA-ccA-ccx-ecn-aaA-caA-caa-caa -ccA-ccA-ccn-ccn-ccK-gaK-gcK-g aK-gaX-gaX-kay-caXaXaXaXcN-caN -ccN-aan-aaN-ccN-caN-ccN-aan-a aN-caN-can-can-ccN-ccN-ccA-ccA -acK-aaX-faXax-faxcX-fcXcK-gaX -haX-H,iJ-cjC-ciJjCjnifjC-giJi JiJiJjCjCjCjCixjqjbhTjq-cixjqj bhTjq-ajb-aixjqjbhTjq-cixjqjbh Tjq-ajb-aiJ-oiyjrjciyiyjrjciyi yjrjciyiyjrjciyiyjrjciyiyjrjci yiyjrjciyiyjrkgjnjU-ajq-ajb-aj q-cjb-ajq-aix-ajU-ajq-ajb-ajq- cjb-ajq-aix-ahT-ckN-akZ-aixjqj bhTjq-cixjqjbhTjq-ajb-aixjqjbh Tjq-cixjqjbhTkN-akK-akK-fiJif- ekK-akZ-gkK-aiu-aiJ-ajb-aky-ck y-bixhT-chT-aky-akN-ckN-cky-ai i-aix-ajb-akg-cjC-ciJ-gkg-cjC- ciJ-gkZ-gkZ-glo-ciu-ciMjFjqiij F-ciMjFjqiijF-ajq-aiMjFjqiijF- ciMjFjqiijF-ajq-akN-ckN-biMii- cii-akN-alc-clc-ckN-aix-aiM-aj C-akZ-fiYiu-ciu-akZ-alo-gkZ-ai J-aiY-ajC-aiY-fiY-J<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#a-tragedy-unsung\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(A Tragedy Unsung)-hdu-cdf-cdu -ccC-acD-acC-acD-acE-acE-abz-c cC-acD-abz-acB-abE-gbE-ecE-aaC -gaC-fcBaT-caT-caT-caT-cba-cba -cba-cba-acD-acK-ccK-ccK-ccK-c cK-ccK-ccK-ccE-acE-acB-acB-acB -acJ-abE-gbE-gbE-gbE-ccE-acJ-a bT-gbT-gbT-gbT-ccE-acE-aba-cba -cba-cba-cba-cba-cba-cba-cbT-g bT-gbT-gdf-cdu-cdt-cdu-cdt-cdu -ccN-ccK-acD-adfdfdfdfbE-ccC-a cD-abE-acE-abE-gcC-acD-abE-acE -abS-gbS-gbS-gbS-ecJ-abT-gbT-g bT-gbT-cdfdfcJ-adf-ddu-cdt-H,- ajCjnifkZ-ckK-aif-akZ-cdY-cbbb bbbbbbbbbbbbbbbbbbbbbdI-caM-cd I-aaa-aaM-cdI-caM-cdI-aaa-abb- kdY-caQ-cdM-caQ-cdM-caQ-cdM-ca Q-cdM-adX-adI-caa-caM-caM-cdI- caa-caM-caM-cbY-cah-aap-aaM-cd I-caM-cdI-aaa-aaM-cdI-caM-cdI- aap-abb-gap-gdX-gdE-epm-aaM-ca M-caa-caa-cdI-cdI-cdp-cdp-cdX- gbb-gdX-gbb-gbh-cbh-cbh-cbh-ce d-cav-cbubububueb-cbf-ceb-aat- abf-ceb-cbf-ceb-aat-abf-cbf-ca t-cat-ceb-ceb-cdI-cdI-adX-abu- gaI-geq-gdX-gbu-dkZ-cjR-H,-lcK -gaKaKaKaKaKaKaKaKaKaKaKaKcA-c aA-ccA-aaa-aaA-ccA-caA-ccA-aaa -aaK-gaK-ccK-caC-ccC-caC-ccC-c aC-ccC-caC-ccC-acK-acA-caa-caA -caA-ccA-caa-caA-caA-cbs-caf-a ak-aaA-ccA-caA-ccA-aaa-aaA-ccA -caA-ccA-aak-aaA-caA-caa-caa-c cA-ccA-ccx-ecn-aaA-caA-caa-caa -ccA-ccA-ccn-ccn-ccK-gaK-gcK-g aK-gaX-gaX-kay-caXaXaXaXcN-caN -ccN-aan-aaN-ccN-caN-ccN-aan-a aN-caN-can-can-ccN-ccN-ccA-ccA -acK-aaX-faXax-faxcX-fcXcK-gaX -haX-H,iJ-cjC-ciJjCjnifjC-giJi JiJiJjCjCjCjCixjqjbhTjq-cixjqj bhTjq-ajb-aixjqjbhTjq-cixjqjbh Tjq-ajb-aiJ-oiyjrjciyiyjrjciyi yjrjciyiyjrjciyiyjrjciyiyjrjci yiyjrjciyiyjrkgjnjU-ajq-ajb-aj q-cjb-ajq-aix-ajU-ajq-ajb-ajq- cjb-ajq-aix-ahT-ckN-akZ-aixjqj bhTjq-cixjqjbhTjq-ajb-aixjqjbh Tjq-cixjqjbhTkN-akK-akK-fiJif- ekK-akZ-gkK-aiu-aiJ-ajb-aky-ck y-bixhT-chT-aky-akN-ckN-cky-ai i-aix-ajb-akg-cjC-ciJ-gkg-cjC- ciJ-gkZ-gkZ-glo-ciu-ciMjFjqiij F-ciMjFjqiijF-ajq-aiMjFjqiijF- ciMjFjqiijF-ajq-akN-ckN-biMii- cii-akN-alc-clc-ckN-aix-aiM-aj C-akZ-fiYiu-ciu-akZ-alo-gkZ-ai J-aiY-ajC-aiY-fiY-J\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"amity\">\n  <h3><a class=\"anchor\" href=\"#amity\" title=\"link to section\">#<\/a>5. Amity<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: NiceDog<\/li>\n      <li>Punk<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222191349&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=6711&amp;Itemid=60\">26 ratings, 26 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Amity)du-acE-abN-bcDbN-bcGaJ- ccz-caa-caa-bcEan-cbS-acE-adf- cdf-adfcBcX-acX-acA-abocBaa-ca a-bcEan-cai-bcGau-acBcBaD-caL- ccF-acH-acK-bbocK-bbocKcDcFcEc z-acB-aaa-caa-bcEan-cbS-acE-ad f-adfbabj-bcBan-can-acIcEch-bb bch-baTbN-ccIcDcIcBan-bcGan-ac IcBaa-bcBah-acB-aaD-gaD-ecE-ab S-gaJ-gcG-acA-acK-bbocK-bbocKc DcFcEcz-acB-abS-gaJ-gba-cba-bc Bam-cam-acD-adf-Z-Z-Z-I,cB-acl -cldefbgkObibrldiOijjHeOeQeTaz oB-cohoh-aohoB-ceTazeTazob-bjr pd-ajGoTon-bjriNijefeRoB-cohoh -aohoB-ceTazeTeZco-ceR-apb-alJ -amSoGmb-aiPikcl-aldefbgkObibr ldiOijjHeOeQeTazoB-cohoh-aohoB -ceTaz-akobu-aeqeeco-afceQbp-a emencp-aeYiubu-aeq-acz-afciuiM -cjNjJjyjubp-aemencp-aeYfcod-c oukNkj-aoc-cjFiijqiinY-alc-ajF iijqiioX-cod-coX-cod-aiu-aaF-a aEatcl-aldefbgkObibrldiOijjHeO eQeTazoB-cohoh-aohoB-ceTazeTaz pi-boRpgmdoGoFop-aoq-amdmb-bjR -acz-Z-Z-Z-G,bL-cbA-acNcPdN-ba VcN-abA-aan-barbD-acQcVdQeAdNa VcQ-abD-aaq-cbA-aan-aaN-acN-ab A-aan-aaN-acNdsbD-acQcVdQeAdNa VcQ-abD-aaq-bateE-cao-acO-abB- cao-acOhwbA-acNcPdN-baVcN-abA- aan-cbD-acQcVdQeAdNaVcQ-abD-aa q-bdKaX-acX-abK-aaxanaT-acT-ab D-aap-aaT-acT-abD-aap-aaT-acT- adueDdueqaT-acT-abD-aap-aaT-ac T-abD-aap-aaU-acU-aeH-adu-aaU- acU-aeH-adu-aaT-acT-aeG-adt-aa T-acT-aeG-adt-adx-ahD-abA-acNc PdN-baVcN-abA-aan-barbD-acQcVd QeAdNaVcQ-abD-aaq-cbD-acQcVdQe AdNaVcQ-abD-aaq-ahB-abK-Z-Z-Z- I,cA-bijjGijov-bkOiNpepd-aoD-a oToTjrjF-aiioc-bnZ-boX-cjq-bii kOijkkauiN-aeckkkO-aij-abg-aiP jtjFiioc-bnZ-boX-cjq-bipiimKox -ajq-aiMiikN-bjFjq-ajFjqjGijov -bkOiNpepd-aoD-aoTjGjrjF-aiioc -bnZ-boX-cjq-ciY-ajR-ajRiujCjR oxocoxocow-ajqkvnY-alclfow-ajq ilnY-alclhow-ajqjvoxocoxocow-a jqjCoxocoxocoX-coFpioR-alJ-aog -aoe-coy-bmLojoglJ-aog-amLmblI oRlI-alJoGmb-ajC-bijjGijov-bkO iNpepd-aoD-aoTjGjrjqjFiioc-bnZ -boX-cjq-bjF-aiioc-bnZ-boX-cjq jC-ajCcz-Z-Z-Z-I<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#amity\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Amity)du-acE-abN-bcDbN-bcGaJ- ccz-caa-caa-bcEan-cbS-acE-adf- cdf-adfcBcX-acX-acA-abocBaa-ca a-bcEan-cai-bcGau-acBcBaD-caL- ccF-acH-acK-bbocK-bbocKcDcFcEc z-acB-aaa-caa-bcEan-cbS-acE-ad f-adfbabj-bcBan-can-acIcEch-bb bch-baTbN-ccIcDcIcBan-bcGan-ac IcBaa-bcBah-acB-aaD-gaD-ecE-ab S-gaJ-gcG-acA-acK-bbocK-bbocKc DcFcEcz-acB-abS-gaJ-gba-cba-bc Bam-cam-acD-adf-Z-Z-Z-I,cB-acl -cldefbgkObibrldiOijjHeOeQeTaz oB-cohoh-aohoB-ceTazeTazob-bjr pd-ajGoTon-bjriNijefeRoB-cohoh -aohoB-ceTazeTeZco-ceR-apb-alJ -amSoGmb-aiPikcl-aldefbgkObibr ldiOijjHeOeQeTazoB-cohoh-aohoB -ceTaz-akobu-aeqeeco-afceQbp-a emencp-aeYiubu-aeq-acz-afciuiM -cjNjJjyjubp-aemencp-aeYfcod-c oukNkj-aoc-cjFiijqiinY-alc-ajF iijqiioX-cod-coX-cod-aiu-aaF-a aEatcl-aldefbgkObibrldiOijjHeO eQeTazoB-cohoh-aohoB-ceTazeTaz pi-boRpgmdoGoFop-aoq-amdmb-bjR -acz-Z-Z-Z-G,bL-cbA-acNcPdN-ba VcN-abA-aan-barbD-acQcVdQeAdNa VcQ-abD-aaq-cbA-aan-aaN-acN-ab A-aan-aaN-acNdsbD-acQcVdQeAdNa VcQ-abD-aaq-bateE-cao-acO-abB- cao-acOhwbA-acNcPdN-baVcN-abA- aan-cbD-acQcVdQeAdNaVcQ-abD-aa q-bdKaX-acX-abK-aaxanaT-acT-ab D-aap-aaT-acT-abD-aap-aaT-acT- adueDdueqaT-acT-abD-aap-aaT-ac T-abD-aap-aaU-acU-aeH-adu-aaU- acU-aeH-adu-aaT-acT-aeG-adt-aa T-acT-aeG-adt-adx-ahD-abA-acNc PdN-baVcN-abA-aan-barbD-acQcVd QeAdNaVcQ-abD-aaq-cbD-acQcVdQe AdNaVcQ-abD-aaq-ahB-abK-Z-Z-Z- I,cA-bijjGijov-bkOiNpepd-aoD-a oToTjrjF-aiioc-bnZ-boX-cjq-bii kOijkkauiN-aeckkkO-aij-abg-aiP jtjFiioc-bnZ-boX-cjq-bipiimKox -ajq-aiMiikN-bjFjq-ajFjqjGijov -bkOiNpepd-aoD-aoTjGjrjF-aiioc -bnZ-boX-cjq-ciY-ajR-ajRiujCjR oxocoxocow-ajqkvnY-alclfow-ajq ilnY-alclhow-ajqjvoxocoxocow-a jqjCoxocoxocoX-coFpioR-alJ-aog -aoe-coy-bmLojoglJ-aog-amLmblI oRlI-alJoGmb-ajC-bijjGijov-bkO iNpepd-aoD-aoTjGjrjqjFiioc-bnZ -boX-cjq-bjF-aiioc-bnZ-boX-cjq jC-ajCcz-Z-Z-Z-I\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"happy-birthday\">\n  <h3><a class=\"anchor\" href=\"#happy-birthday\" title=\"link to section\">#<\/a>6. Happy Birthday!<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Cyros Lugoth<\/li>\n      <li>Punk<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li>25 ratings, 26 comments<\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Happy Birthday!)-GcB-adndu-ba b-gab-ecD-aaf-aaf-gag-bcDan-ca u-gau-gau-gau-gab-gab-ecD-aaf- aaf-gag-bcDdf-Z-Z-Z-Z-Z-R,aXbN bb-acScz-baXbNbb-adEcS-baXfveq -acSczbN-ceFeqcS-adEcS-ccQ-baX bNbb-acSco-baXbNbb-adEcH-baXfv eq-acSczbN-ceFeqcS-adEcS-ccH-c bC-caQ-caQ-ccH-cbC-caQ-cco-baX bNbb-acSco-baXbNbb-adEcH-baXfv eq-acSczbN-ceFeqcS-adEcS-cbbbN bbcg-Z-Z-Z-Z-Z-K,aHbkaK-abXbK- baHbkaK-acxbX-baHdKcX-abXbKbk- cdhcXbX-acxbX-cbP-adC-abaaA-ab NbA-baAbaaA-acnbN-baAdAcN-abNb Aba-cdacNbN-acnbN-cbP-cbc-caC- caC-cbP-cbc-caC-cbC-cbaaA-abNb A-baAbaaA-acnbN-baAdAcN-abNbAb a-cdacNbN-acnbX-cdKekdKex-Z-Z- Z-Z-Z-K,-Ekh-cke-cjeiziA-ajI-c jeiziA-cjX-cjX-ajJ-ajf-cix-ckg -cix-alc-ahT-ajb-alg-aiB-chTlc ix-alc-ahT-aky-ajJ-aiB-cjJ-ajf ixiB-ajJ-cjfixiB-cjY-cjY-ajI-a je-cix-ckg-Z-Z-Z-Z-Z-R<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#happy-birthday\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Happy Birthday!)-GcB-adndu-ba b-gab-ecD-aaf-aaf-gag-bcDan-ca u-gau-gau-gau-gab-gab-ecD-aaf- aaf-gag-bcDdf-Z-Z-Z-Z-Z-R,aXbN bb-acScz-baXbNbb-adEcS-baXfveq -acSczbN-ceFeqcS-adEcS-ccQ-baX bNbb-acSco-baXbNbb-adEcH-baXfv eq-acSczbN-ceFeqcS-adEcS-ccH-c bC-caQ-caQ-ccH-cbC-caQ-cco-baX bNbb-acSco-baXbNbb-adEcH-baXfv eq-acSczbN-ceFeqcS-adEcS-cbbbN bbcg-Z-Z-Z-Z-Z-K,aHbkaK-abXbK- baHbkaK-acxbX-baHdKcX-abXbKbk- cdhcXbX-acxbX-cbP-adC-abaaA-ab NbA-baAbaaA-acnbN-baAdAcN-abNb Aba-cdacNbN-acnbN-cbP-cbc-caC- caC-cbP-cbc-caC-cbC-cbaaA-abNb A-baAbaaA-acnbN-baAdAcN-abNbAb a-cdacNbN-acnbX-cdKekdKex-Z-Z- Z-Z-Z-K,-Ekh-cke-cjeiziA-ajI-c jeiziA-cjX-cjX-ajJ-ajf-cix-ckg -cix-alc-ahT-ajb-alg-aiB-chTlc ix-alc-ahT-aky-ajJ-aiB-cjJ-ajf ixiB-ajJ-cjfixiB-cjY-cjY-ajI-a je-cix-ckg-Z-Z-Z-Z-Z-R\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"bid-farewell\">\n  <h3><a class=\"anchor\" href=\"#bid-farewell\" title=\"link to section\">#<\/a>7. Bid Farewell<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Anomaly<\/li>\n      <li>Hard Rodk<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222034250&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=5172&amp;Itemid=60\">24 ratings, 27 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Bid Farewell)du-wdu-cat-gat-f cBat-gat-ccz-cax-gax-ecC-aat-f cLat-cdf-bcCat-gat-ecIcDat-gat -ecD-aaO-gaO-edf-GdodpcZcEbv-g bv-ecD-adt-cdu-cbv-gbv-gbv-gbv -ccC-adf-adt-cdu-cdt-Adu-cbT-e cC-abT-ecz-abT-cbTbTbTbTbT-gbF -gbF-gbF-gbF-ecG-adt-cdu-cdt-c du-cdt-cdu-cdt-cdu-cdt-gdu-cdt -Z-g,dY-clx-clv-clz-cly-bkZ-hk Z-cjC-ckv-ckg-cdM-cdM-cda-ccH- cfG-cfF-cfG-cfF-adQ-cdQ-cdQ-cd Q-aly-cdM-cdM-cda-cda-cdM-cdM- cda-cda-cfD-gfD-edX-ehf-faDhf- faDhf-faDhf-faDbm-caA-acpcWbm- caA-acsccnI-cnH-cbm-acudgaA-ac pbRbm-acucvbY-acpbZbm-acudgaA- acpbRbm-acucvbY-aczcgbu-gnf-gn g-cnb-bkNnj-gnj-cnk-cni-cni-ak a-ani-cnimxjUjqnj-cnjnjnjnjnj- cnk-chTjqjUjqkNjUiMjqiMixiMixk jjqjUkNjU-cjU-cjq-cjU-ckg-gjC- ciY-ajz-akg-gkv-cif-aiYjCjC-ga q-cap-Z-g,cL-scM-gcA-ccA-ccA-c cA-ccA-ccA-ccA-ccA-gaY-cfh-cfg -acC-ccC-ccC-ccC-acJ-ccA-ccA-c cA-ccA-ccA-ccA-ccA-ccA-gaY-cfe -AaN-caN-caN-caN-caN-caN-caN-c aN-caX-gaN-caN-caN-caN-caN-caN -caN-caN-abKbxaX-cal-Aam-gaa-c aa-caa-caa-caa-cagagagagaa-caa -caa-caa-caa-caa-caa-caa-caa-c aa-aaI-aak-cal-cak-cal-cak-cal -cak-caaahaI-adi-adI-acI-adi-a cK-cak-Z-g,la-clK-clH-clG-clL- biJ-hiJ-ckZ-cjC-ciY-biYix-ckN- cjq-ciM-biYdV-glK-clH-blM-clMl L-blLlK-clL-ckQ-ciA-chW-ciP-ci A-cjt-ciP-cjX-biUdV-gkVibiFibk ViblM-akZ-koc-cii-aiMiioc-cii- akNkjoc-cii-aiMiioc-cii-aiMiio c-cii-akNkjnM-cnG-cbu-najoy-co z-coC-cox-ciM-ciM-ciM-cix-akNi xkj-ckN-aiMixiM-cix-akNixkj-ck N-aiMixiM-cix-akNixkj-ckN-aiMi xiM-cix-akNixkj-ckN-aiMixiM-ci x-akNixkj-ckN-aiMixiM-cix-akNi xkj-ckN-aiMixiM-cix-akNixkj-ck N-aiMixiM-cix-akNixkj-ckN-aiMi xiJ-geK-ceJ-Z-g<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#bid-farewell\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Bid Farewell)du-wdu-cat-gat-f cBat-gat-ccz-cax-gax-ecC-aat-f cLat-cdf-bcCat-gat-ecIcDat-gat -ecD-aaO-gaO-edf-GdodpcZcEbv-g bv-ecD-adt-cdu-cbv-gbv-gbv-gbv -ccC-adf-adt-cdu-cdt-Adu-cbT-e cC-abT-ecz-abT-cbTbTbTbTbT-gbF -gbF-gbF-gbF-ecG-adt-cdu-cdt-c du-cdt-cdu-cdt-cdu-cdt-gdu-cdt -Z-g,dY-clx-clv-clz-cly-bkZ-hk Z-cjC-ckv-ckg-cdM-cdM-cda-ccH- cfG-cfF-cfG-cfF-adQ-cdQ-cdQ-cd Q-aly-cdM-cdM-cda-cda-cdM-cdM- cda-cda-cfD-gfD-edX-ehf-faDhf- faDhf-faDhf-faDbm-caA-acpcWbm- caA-acsccnI-cnH-cbm-acudgaA-ac pbRbm-acucvbY-acpbZbm-acudgaA- acpbRbm-acucvbY-aczcgbu-gnf-gn g-cnb-bkNnj-gnj-cnk-cni-cni-ak a-ani-cnimxjUjqnj-cnjnjnjnjnj- cnk-chTjqjUjqkNjUiMjqiMixiMixk jjqjUkNjU-cjU-cjq-cjU-ckg-gjC- ciY-ajz-akg-gkv-cif-aiYjCjC-ga q-cap-Z-g,cL-scM-gcA-ccA-ccA-c cA-ccA-ccA-ccA-ccA-gaY-cfh-cfg -acC-ccC-ccC-ccC-acJ-ccA-ccA-c cA-ccA-ccA-ccA-ccA-ccA-gaY-cfe -AaN-caN-caN-caN-caN-caN-caN-c aN-caX-gaN-caN-caN-caN-caN-caN -caN-caN-abKbxaX-cal-Aam-gaa-c aa-caa-caa-caa-cagagagagaa-caa -caa-caa-caa-caa-caa-caa-caa-c aa-aaI-aak-cal-cak-cal-cak-cal -cak-caaahaI-adi-adI-acI-adi-a cK-cak-Z-g,la-clK-clH-clG-clL- biJ-hiJ-ckZ-cjC-ciY-biYix-ckN- cjq-ciM-biYdV-glK-clH-blM-clMl L-blLlK-clL-ckQ-ciA-chW-ciP-ci A-cjt-ciP-cjX-biUdV-gkVibiFibk ViblM-akZ-koc-cii-aiMiioc-cii- akNkjoc-cii-aiMiioc-cii-aiMiio c-cii-akNkjnM-cnG-cbu-najoy-co z-coC-cox-ciM-ciM-ciM-cix-akNi xkj-ckN-aiMixiM-cix-akNixkj-ck N-aiMixiM-cix-akNixkj-ckN-aiMi xiM-cix-akNixkj-ckN-aiMixiM-ci x-akNixkj-ckN-aiMixiM-cix-akNi xkj-ckN-aiMixiM-cix-akNixkj-ck N-aiMixiM-cix-akNixkj-ckN-aiMi xiJ-geK-ceJ-Z-g\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"fly-free\">\n  <h3><a class=\"anchor\" href=\"#fly-free\" title=\"link to section\">#<\/a>8. Fly Free!<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Cyros Lugoth<\/li>\n      <li>Punk<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li>22 ratings, 22 comments<\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Fly Free!)-ncJdpab-gab-ecD-aa D-gaD-ecF-abp-gbp-ecC-aaK-caK- caK-ecA-aab-gaa-gbz-cbz-cbz-ec C-acX-cab-bbzab-basab-bbzab-ac D-abz-bbEbz-bbEbz-bbLbz-acD-ab M-gbF-ccK-acLcJcfdocfcYcfdncfc Icf-fcMaC-gaD-ecFcDcL-ccL-ccL- ccL-bbaaC-gaC-ecG-adododododod odocDab-gaa-ecB-aab-bbzab-basa b-bbzab-acD-aaE-caE-caE-caE-ac D-adg-adg-adg-adg-adg-adg-adg- adg-adt-Z-Z-I,bu-abs-acz-acx-a bu-abs-aaI-ahkczbl-caz-adc-abl -caz-acq-abg-cau-acl-abg-cau-a ec-abj-bhgax-acohDbj-bhgax-aef hRax-cco-abj-aax-cbjawbp-abk-c ay-cbk-ccp-cbk-cay-cbk-ccp-cdb -acp-abl-caz-adc-abl-caz-acq-a bl-caz-adc-abl-caz-acq-ahE-ahK -caz-ahE-ahK-cay-abf-cat-acW-a bf-cat-ack-abj-cax-ada-abj-cax -aco-abf-cat-cbf-cat-cbf-cck-c dI-ceb-aeN-abg-cau-aaH-abk-cay -cbk-ceg-adN-abl-caz-adc-abl-c az-acq-abj-cax-ada-abj-cax-aco -abu-aaI-abu-acz-abu-aaI-acz-a aI-adl-Z-Z-I,-meL-bdP-cdp-acc- adP-cdp-aeC-aaO-cao-abB-aaO-ca o-acO-adN-cdn-aeA-adN-cdn-acN- adv-adv-aeI-adV-adv-adv-adWdwd O-aaVdNaTdUavdnatduaVdNaTdUbIe AbGeHaVdNaTdUavdnatduaVdNaTdUb IeAbGeHch-abH-adP-cdp-acc-adP- cdp-aeC-adP-cdp-acc-adP-cdp-ae C-abJcaci-abJcNav-abJcaci-abJc Nav-adO-cdo-acb-adO-cdo-aeB-ad O-cdo-acb-adO-cdo-aeB-adUaUdUa UduauduaudUaUdUaUduauduauaP-bd ObC-beBcC-bencPdOav-aaN-can-ad p-aaVdNaTdUavdnatduaVdNaTdUcP- acC-adP-cdp-acc-adP-cdp-aeC-ad P-cdp-acc-adP-cdp-aeC-adX-adx- adX-aeK-adX-adx-aeK-adx-adx-Z- Z-I,oc-aoZiuoc-aoZjRoc-aoZiuoc -aoZjRoc-aoZiuoc-aoZjRoc-aoZiu oc-aoZiUiNov-aoNij-aoD-aiNov-a oNij-apd-aiNol-boTjrijobiNol-b oTjroa-aob-cob-aiNkOob-bobiOil iT-ajRiY-ajRiu-api-aiY-coX-cjR iY-ajRiu-api-aiY-coX-ajFjqiQ-c oc-aoZiuoc-aoZjRoc-aoZiuoc-aoZ iUoc-aoZiuoc-aoZjRoc-aoZiuoc-a oZiQiY-maJ-ahf-ahkaIhf-ahkczhf -ahkaIhf-ahkczhf-ahkaIhf-ahkcz oc-aoZiuoc-aoZiUpf-api-apflKoo oRlJ-aph-aoGmb-alIoA-cop-aoF-a or-boqpgoQpg-aczbu-aczaI-aaG-a jRiY-ajRiu-api-aiY-ciMlciMkNoc -aoZiuoc-aoZjRoc-aoZiuoc-aoZiQ oc-aoZiuoc-aoZjRoc-aoZiuoc-aoZ kZoYiuowiYoY-anZ-aoYiuoxjCowkZ iukZiY-Z-Z-I<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#fly-free\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Fly Free!)-ncJdpab-gab-ecD-aa D-gaD-ecF-abp-gbp-ecC-aaK-caK- caK-ecA-aab-gaa-gbz-cbz-cbz-ec C-acX-cab-bbzab-basab-bbzab-ac D-abz-bbEbz-bbEbz-bbLbz-acD-ab M-gbF-ccK-acLcJcfdocfcYcfdncfc Icf-fcMaC-gaD-ecFcDcL-ccL-ccL- ccL-bbaaC-gaC-ecG-adododododod odocDab-gaa-ecB-aab-bbzab-basa b-bbzab-acD-aaE-caE-caE-caE-ac D-adg-adg-adg-adg-adg-adg-adg- adg-adt-Z-Z-I,bu-abs-acz-acx-a bu-abs-aaI-ahkczbl-caz-adc-abl -caz-acq-abg-cau-acl-abg-cau-a ec-abj-bhgax-acohDbj-bhgax-aef hRax-cco-abj-aax-cbjawbp-abk-c ay-cbk-ccp-cbk-cay-cbk-ccp-cdb -acp-abl-caz-adc-abl-caz-acq-a bl-caz-adc-abl-caz-acq-ahE-ahK -caz-ahE-ahK-cay-abf-cat-acW-a bf-cat-ack-abj-cax-ada-abj-cax -aco-abf-cat-cbf-cat-cbf-cck-c dI-ceb-aeN-abg-cau-aaH-abk-cay -cbk-ceg-adN-abl-caz-adc-abl-c az-acq-abj-cax-ada-abj-cax-aco -abu-aaI-abu-acz-abu-aaI-acz-a aI-adl-Z-Z-I,-meL-bdP-cdp-acc- adP-cdp-aeC-aaO-cao-abB-aaO-ca o-acO-adN-cdn-aeA-adN-cdn-acN- adv-adv-aeI-adV-adv-adv-adWdwd O-aaVdNaTdUavdnatduaVdNaTdUbIe AbGeHaVdNaTdUavdnatduaVdNaTdUb IeAbGeHch-abH-adP-cdp-acc-adP- cdp-aeC-adP-cdp-acc-adP-cdp-ae C-abJcaci-abJcNav-abJcaci-abJc Nav-adO-cdo-acb-adO-cdo-aeB-ad O-cdo-acb-adO-cdo-aeB-adUaUdUa UduauduaudUaUdUaUduauduauaP-bd ObC-beBcC-bencPdOav-aaN-can-ad p-aaVdNaTdUavdnatduaVdNaTdUcP- acC-adP-cdp-acc-adP-cdp-aeC-ad P-cdp-acc-adP-cdp-aeC-adX-adx- adX-aeK-adX-adx-aeK-adx-adx-Z- Z-I,oc-aoZiuoc-aoZjRoc-aoZiuoc -aoZjRoc-aoZiuoc-aoZjRoc-aoZiu oc-aoZiUiNov-aoNij-aoD-aiNov-a oNij-apd-aiNol-boTjrijobiNol-b oTjroa-aob-cob-aiNkOob-bobiOil iT-ajRiY-ajRiu-api-aiY-coX-cjR iY-ajRiu-api-aiY-coX-ajFjqiQ-c oc-aoZiuoc-aoZjRoc-aoZiuoc-aoZ iUoc-aoZiuoc-aoZjRoc-aoZiuoc-a oZiQiY-maJ-ahf-ahkaIhf-ahkczhf -ahkaIhf-ahkczhf-ahkaIhf-ahkcz oc-aoZiuoc-aoZiUpf-api-apflKoo oRlJ-aph-aoGmb-alIoA-cop-aoF-a or-boqpgoQpg-aczbu-aczaI-aaG-a jRiY-ajRiu-api-aiY-ciMlciMkNoc -aoZiuoc-aoZjRoc-aoZiuoc-aoZiQ oc-aoZiuoc-aoZjRoc-aoZiuoc-aoZ kZoYiuowiYoY-anZ-aoYiuoxjCowkZ iukZiY-Z-Z-I\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"pursuit-of-happiness\">\n  <h3><a class=\"anchor\" href=\"#pursuit-of-happiness\" title=\"link to section\">#<\/a>9. Pursuit of Happiness<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: MuFFiNz<\/li>\n      <li>Classic Rock<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li>22 ratings, 23 comments<\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Pursuit of Happiness)cP-ccP-c cP-ccP-cdldldldldldldldldldldl dldldldlcJbb-cbb-cbb-cbb-cbb-c bb-cbb-cbb-bcJcu-gcu-gcs-gcs-g cs-gcs-gaK-gaL-gaD-gaDahaDahaD asaDcBbp-cbp-bbpbq-cbq-cbp-cbp -bbpbq-cbq-bcEaT-caT-caT-cbb-a aTcHdodlcYdldodlcYdldodlcYdldl dldldldldldldldldldldldldldlcJ dldldldldldldldldldldldldldldl cJbb-cbb-cbb-cbb-cbb-cbb-cbb-c bb-aaTcJdf-kaT-acE-abb-cbb-cbb -cbb-cbb-cbb-cbb-cbb-acBcDdf-Z -Z-s,dJ-cbg-cbS-cbg-cdJ-cbg-cb S-cbg-bcddI-adN-abf-abk-abR-ab VbUdI-adpdtdI-adN-abf-abk-abR- abVbUdI-abf-adJ-abS-acE-abg-ad J-abS-abg-abS-adL-abU-acG-abi- abU-adL-abi-abU-adLdMbUbVcGcHb ibjbUbVdLdMbibjbUbRdM-abV-acH- abj-adM-abV-abj-abV-adMdIbVbRc HcDbjbfdMdIbVbRbjbfbVbRdI-adN- abf-abk-abR-abVbUdI-adpdtdI-ad N-abf-abk-abR-abV-adI-abf-adN- ccI-abk-abW-bbZbk-abWcddY-bdFc T-bdFch-adF-adY-cbv-cch-cbv-cd J-cbg-cbS-cbg-abScddI-bdMbf-bb jbV-cbk-abV-adI-bdMbR-bbVcD-bc Hbf-bbjdX-ccg-cbu-ccg-cdI-adN- abf-abk-abR-abVbUdI-adpdtdI-ad N-abf-abk-abR-abVbUdI-abf-adV- Z-Z-s,cBcJcI-aaOaWaV-abobwbvev aO-ccBcJcI-aaOaWaV-abobwbvevaO -bbxcA-acG-aaN-adP-abn-aeo-acA -acn-acA-acG-aaN-adP-abn-aeo-a cA-aaN-acC-abp-abP-aaP-acC-abp -aaP-abp-acC-abp-abP-aaP-abp-a cC-aaP-abp-acC-abp-abP-aaP-abp -acC-aaP-abp-acA-abn-abN-aaN-a cD-abq-aaQ-abq-acBcGbobtbObTaO aTcBcGbobtaOaTbobtcA-acG-aaN-a dN-abn-aen-acA-acn-acA-acC-aaN -adR-abn-aen-acA-aaN-acB-cePbN dPaNet-caPdPboencL-b!!bY-b!!by -ccG-acHcBaT-aaUaObt-abubodP-a dCdccC-bcBaP-baObp-bboaP-abp-a cA-caN-cbn-caN-aep-acA-cbn-cbN -caN-ccK-cbx-caX-cbx-ccA-acG-a aN-adP-abn-aeo-acA-acn-acA-acG -aaN-adP-abn-aeo-acA-aaN-acJ-Z -Z-s,iy-ahU-aiy-ahUkOkz-akOhUm P-aiyhUiy-ahUmOiy-ahUkOhU-aiyi NmPjriNhTnx-cnx-anw-akykNkykNm i-bmknx-ajUjqnx-amh-akykNhTixm I-amFkykZ-oix-ahTkNixiMixkNixj qjUjqixjqixhTix-ahT-akNixkN-ah T-aixjqjq-bhTix-ahTkNixiMixhTm F-amHmnmJ-aly-amk-cmkmkhThTmk- ajqhTkN-ahTixnx-cnx-anw-akykNk ykNmi-bmknx-ajUjqnx-amh-akykNh TixmI-amFkymj-cmI-ami-aif-aiJi fkZ-akKkZkZ-kiK-aig-aiK-aiglak L-alaigiZjDiKigiK-aig-aiK-aigl aig-aiKiZjDkhiKiamS-bmtmb-amtm RlG-bmSmr-alH-amu-anB-amb-elG- amS-amlhTiJ-bjCif-biJkZ-biJif- aiJjCnx-cnx-anw-akykNkykNmi-bm knx-ajUjqnx-amh-akykNhTixmI-aj UixkX-Z-Z-s<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#pursuit-of-happiness\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Pursuit of Happiness)cP-ccP-c cP-ccP-cdldldldldldldldldldldl dldldldlcJbb-cbb-cbb-cbb-cbb-c bb-cbb-cbb-bcJcu-gcu-gcs-gcs-g cs-gcs-gaK-gaL-gaD-gaDahaDahaD asaDcBbp-cbp-bbpbq-cbq-cbp-cbp -bbpbq-cbq-bcEaT-caT-caT-cbb-a aTcHdodlcYdldodlcYdldodlcYdldl dldldldldldldldldldldldldldlcJ dldldldldldldldldldldldldldldl cJbb-cbb-cbb-cbb-cbb-cbb-cbb-c bb-aaTcJdf-kaT-acE-abb-cbb-cbb -cbb-cbb-cbb-cbb-cbb-acBcDdf-Z -Z-s,dJ-cbg-cbS-cbg-cdJ-cbg-cb S-cbg-bcddI-adN-abf-abk-abR-ab VbUdI-adpdtdI-adN-abf-abk-abR- abVbUdI-abf-adJ-abS-acE-abg-ad J-abS-abg-abS-adL-abU-acG-abi- abU-adL-abi-abU-adLdMbUbVcGcHb ibjbUbVdLdMbibjbUbRdM-abV-acH- abj-adM-abV-abj-abV-adMdIbVbRc HcDbjbfdMdIbVbRbjbfbVbRdI-adN- abf-abk-abR-abVbUdI-adpdtdI-ad N-abf-abk-abR-abV-adI-abf-adN- ccI-abk-abW-bbZbk-abWcddY-bdFc T-bdFch-adF-adY-cbv-cch-cbv-cd J-cbg-cbS-cbg-abScddI-bdMbf-bb jbV-cbk-abV-adI-bdMbR-bbVcD-bc Hbf-bbjdX-ccg-cbu-ccg-cdI-adN- abf-abk-abR-abVbUdI-adpdtdI-ad N-abf-abk-abR-abVbUdI-abf-adV- Z-Z-s,cBcJcI-aaOaWaV-abobwbvev aO-ccBcJcI-aaOaWaV-abobwbvevaO -bbxcA-acG-aaN-adP-abn-aeo-acA -acn-acA-acG-aaN-adP-abn-aeo-a cA-aaN-acC-abp-abP-aaP-acC-abp -aaP-abp-acC-abp-abP-aaP-abp-a cC-aaP-abp-acC-abp-abP-aaP-abp -acC-aaP-abp-acA-abn-abN-aaN-a cD-abq-aaQ-abq-acBcGbobtbObTaO aTcBcGbobtaOaTbobtcA-acG-aaN-a dN-abn-aen-acA-acn-acA-acC-aaN -adR-abn-aen-acA-aaN-acB-cePbN dPaNet-caPdPboencL-b!!bY-b!!by -ccG-acHcBaT-aaUaObt-abubodP-a dCdccC-bcBaP-baObp-bboaP-abp-a cA-caN-cbn-caN-aep-acA-cbn-cbN -caN-ccK-cbx-caX-cbx-ccA-acG-a aN-adP-abn-aeo-acA-acn-acA-acG -aaN-adP-abn-aeo-acA-aaN-acJ-Z -Z-s,iy-ahU-aiy-ahUkOkz-akOhUm P-aiyhUiy-ahUmOiy-ahUkOhU-aiyi NmPjriNhTnx-cnx-anw-akykNkykNm i-bmknx-ajUjqnx-amh-akykNhTixm I-amFkykZ-oix-ahTkNixiMixkNixj qjUjqixjqixhTix-ahT-akNixkN-ah T-aixjqjq-bhTix-ahTkNixiMixhTm F-amHmnmJ-aly-amk-cmkmkhThTmk- ajqhTkN-ahTixnx-cnx-anw-akykNk ykNmi-bmknx-ajUjqnx-amh-akykNh TixmI-amFkymj-cmI-ami-aif-aiJi fkZ-akKkZkZ-kiK-aig-aiK-aiglak L-alaigiZjDiKigiK-aig-aiK-aigl aig-aiKiZjDkhiKiamS-bmtmb-amtm RlG-bmSmr-alH-amu-anB-amb-elG- amS-amlhTiJ-bjCif-biJkZ-biJif- aiJjCnx-cnx-anw-akykNkykNmi-bm knx-ajUjqnx-amh-akykNhTixmI-aj UixkX-Z-Z-s\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"revolution-hour\">\n  <h3><a class=\"anchor\" href=\"#revolution-hour\" title=\"link to section\">#<\/a>10. Revolution Hour<\/h3>\n  \n    <ul class=\"horizontal\">\n      <li>Author: Mergullion<\/li>\n      <li>Hard Rock<\/li>\n      <li>Rating: 10.00 &#x2F; 10.00<\/li>\n      \n        <li><a href=\"https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20101222034107&#x2F;http:&#x2F;&#x2F;punk-o-matic.net&#x2F;index.php?option=com_usercontents&amp;task=displaycontentdetails&amp;contentid=10915&amp;Itemid=60\">21 ratings, 22 comments<\/a><\/li>\n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Revolution Hour)cDcDcDcDaf-ca f-caf-caf-cas-cas-cas-cas-caa- ccDcDcDcDab-ccDcDcDcDaf-ccDcCc DcCag-ccDcCcDcCaf-gaf-gaf-caf- cag-cag-acD-aag-cag-cag-gau-ga u-ccBcBcC-aau-gau-cam-acD-aab- gab-gas-cad-cas-cascAcD-aab-ga b-ccz-cdf-gaC-abz-aaC-aby-aag- ccDcDcDcDaf-caf-cag-cag-acD-aa g-cag-cag-gau-gau-ccBcBcC-aau- gau-cam-acD-acDcDcDcDcG-abA-gb A-ecB-abM-abF-abM-abF-abM-abF- acz-cdf-fdu-cdfau-gau-ccz-cau- gau-cam-acD-aaB-gaB-cam-acA-aa B-gaB-cam-acA-adg-acH-adf-acDc Ddf-G,-dbfbgbfbgckclckclbfbgbf cWckclckcWbfbgbfbgckclckclbfbg bfcWckclckcWbk-cbh-cbk-cbh-cbk -cbh-cbk-cbh-cbu-caI-cbu-caI-c bf-ackbRck-acWckcW-aebdIeb-aeN -aiM-ajFjqjF-akjjFjF-clc-aii-a cp-cdb-ceg-ceN-ccp-cdb-ceg-ceN -cjF-ajqjFjq-aii-aiM-bnhhT-bjq jF-bkyjq-ciM-ajRkgjF-ccn-caw-c bf-cbf-caI-gbf-aat-abf-aatbRck -cpm-cbf-ackbRck-acWckcW-aebdI eb-aeN-aiM-ajFjqjF-akjjFjF-clc -aii-acp-cdb-ceg-ceN-ccp-cdb-c eg-ceN-ccz-eckclckdqckclckbzck dpdpbzoF-ccz-ccz-gcA-ccz-jpocp -cdb-ceg-ceSeSeSegcp-cdb-ceg-c eN-cck-acWckcW-aebdIeb-ceN-beb ck-acWckcW-aebdIeb-ceN-ccz-ccz -K,-daN-cbA-caN-bcabA-bcaaN-cb A-caN-bcabA-bcaaN-caNbAaNbAaN- caNbAcabAaN-caNbAaNbAaN-caNbAc abAaN-can-caN-can-caN-cbA-cca- ccN-adn-aaN-cbA-cca-ccN-adn-ab D-ccd-ccQ-cdn-cbD-ccd-ccQ-cdn- cbA-can-caN-caa-cbA-can-caN-cb A-cbC-cap-caP-caP-cax-gaN-aan- aaN-aanbnbA-cbA-aaN-aaN-cbA-cc a-ccN-adn-aaN-cbA-cca-ccN-adn- abD-ccd-ccQ-cdn-cbD-ccd-ccQ-cd n-cbK-ebA-bcnbA-bbabA-cbA-cbK- cbK-cbK-cbL-cbA-aca-acN-adn-ab D-bbJbD-ccd-ccQ-cdq-cbD-ccd-cc Q-cdn-cbA-cca-ccN-cdn-bcNbA-cc a-ccN-cdn-cbK-cbK-cbK-G,-dbfbg bfbgckclckclbfbgbfcWckclckcWiM iViMiUjFjOjFjNiM-ajFkjjF-ciM-c bfckbfckiM-cbk-ciM-cbfckbfckiM -cbf-chh-coc-chi-cod-cbk-ccp-c db-ceg-aeS-abk-ccp-cdb-akjkNjF -cjF-bjqjF-bjqjF-bjqjF-bkjjF-b jqjF-bkjjF-bjqjF-bkjcl-cau-cbg -cab-cck-cat-cbf-cck-cco-cax-c bj-cbj-ciw-giMjqiikNiMjqiijqjF -cpo-cbk-ccp-cdb-ceg-aeS-abk-c cp-cdb-akjkNjF-cjF-bjqjF-bjqjF -bjqjF-bkjjF-bjqjF-bkjjF-bjqjF -bkjjR-eoG-coF-coz-coG-giu-gjS -bkypm-jpmjF-bjqjF-bjqjF-bjqjF -bkjjF-bjqjF-bkjjF-bjqjF-bkjjM -cjM-cjM-cjF-bkjjJ-ajH-ajJ-ajH -ajJ-ajH-ajJjJjJkjjR-O<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#revolution-hour\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Revolution Hour)cDcDcDcDaf-ca f-caf-caf-cas-cas-cas-cas-caa- ccDcDcDcDab-ccDcDcDcDaf-ccDcCc DcCag-ccDcCcDcCaf-gaf-gaf-caf- cag-cag-acD-aag-cag-cag-gau-ga u-ccBcBcC-aau-gau-cam-acD-aab- gab-gas-cad-cas-cascAcD-aab-ga b-ccz-cdf-gaC-abz-aaC-aby-aag- ccDcDcDcDaf-caf-cag-cag-acD-aa g-cag-cag-gau-gau-ccBcBcC-aau- gau-cam-acD-acDcDcDcDcG-abA-gb A-ecB-abM-abF-abM-abF-abM-abF- acz-cdf-fdu-cdfau-gau-ccz-cau- gau-cam-acD-aaB-gaB-cam-acA-aa B-gaB-cam-acA-adg-acH-adf-acDc Ddf-G,-dbfbgbfbgckclckclbfbgbf cWckclckcWbfbgbfbgckclckclbfbg bfcWckclckcWbk-cbh-cbk-cbh-cbk -cbh-cbk-cbh-cbu-caI-cbu-caI-c bf-ackbRck-acWckcW-aebdIeb-aeN -aiM-ajFjqjF-akjjFjF-clc-aii-a cp-cdb-ceg-ceN-ccp-cdb-ceg-ceN -cjF-ajqjFjq-aii-aiM-bnhhT-bjq jF-bkyjq-ciM-ajRkgjF-ccn-caw-c bf-cbf-caI-gbf-aat-abf-aatbRck -cpm-cbf-ackbRck-acWckcW-aebdI eb-aeN-aiM-ajFjqjF-akjjFjF-clc -aii-acp-cdb-ceg-ceN-ccp-cdb-c eg-ceN-ccz-eckclckdqckclckbzck dpdpbzoF-ccz-ccz-gcA-ccz-jpocp -cdb-ceg-ceSeSeSegcp-cdb-ceg-c eN-cck-acWckcW-aebdIeb-ceN-beb ck-acWckcW-aebdIeb-ceN-ccz-ccz -K,-daN-cbA-caN-bcabA-bcaaN-cb A-caN-bcabA-bcaaN-caNbAaNbAaN- caNbAcabAaN-caNbAaNbAaN-caNbAc abAaN-can-caN-can-caN-cbA-cca- ccN-adn-aaN-cbA-cca-ccN-adn-ab D-ccd-ccQ-cdn-cbD-ccd-ccQ-cdn- cbA-can-caN-caa-cbA-can-caN-cb A-cbC-cap-caP-caP-cax-gaN-aan- aaN-aanbnbA-cbA-aaN-aaN-cbA-cc a-ccN-adn-aaN-cbA-cca-ccN-adn- abD-ccd-ccQ-cdn-cbD-ccd-ccQ-cd n-cbK-ebA-bcnbA-bbabA-cbA-cbK- cbK-cbK-cbL-cbA-aca-acN-adn-ab D-bbJbD-ccd-ccQ-cdq-cbD-ccd-cc Q-cdn-cbA-cca-ccN-cdn-bcNbA-cc a-ccN-cdn-cbK-cbK-cbK-G,-dbfbg bfbgckclckclbfbgbfcWckclckcWiM iViMiUjFjOjFjNiM-ajFkjjF-ciM-c bfckbfckiM-cbk-ciM-cbfckbfckiM -cbf-chh-coc-chi-cod-cbk-ccp-c db-ceg-aeS-abk-ccp-cdb-akjkNjF -cjF-bjqjF-bjqjF-bjqjF-bkjjF-b jqjF-bkjjF-bjqjF-bkjcl-cau-cbg -cab-cck-cat-cbf-cck-cco-cax-c bj-cbj-ciw-giMjqiikNiMjqiijqjF -cpo-cbk-ccp-cdb-ceg-aeS-abk-c cp-cdb-akjkNjF-cjF-bjqjF-bjqjF -bjqjF-bkjjF-bjqjF-bkjjF-bjqjF -bkjjR-eoG-coF-coz-coG-giu-gjS -bkypm-jpmjF-bjqjF-bjqjF-bjqjF -bkjjF-bjqjF-bkjjF-bjqjF-bkjjM -cjM-cjM-cjF-bkjjJ-ajH-ajJ-ajH -ajJ-ajH-ajJjJjJkjjR-O\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n"},{"title":"My Picks","published":"2024-03-18T00:00:00+00:00","updated":"2024-03-18T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/punkomatic\/my-picks\/"}},"id":"https:\/\/iliazeus.lol\/punkomatic\/my-picks\/","content":"<p>These are some of the good Punk-o-Matic 2 songs I salvaged from various places, in no particular order.<\/p>\n<hgroup class=\"punkomatic-song\" id=\"rebirth\">\n  <h3><a class=\"anchor\" href=\"#rebirth\" title=\"link to section\">#<\/a>evil-dog \u2014 Rebirth<\/h3>\n  \n    <p><p>This is my favorite of the songs that were included with Punk-O-Matic 2.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Rebirth)-vdpdododf-gdpdododf-cdu-ccK-ccK-ccK-ccK-ccK-ccK-ccK-ccK-acD-aaX-caX-caX-caX-cak-cak-cak-cak-cbP-cbP-cbP-abP-abPbPcH-acB-acB-acB-acB-acB-acB-acBcBdg-adu-cdr-cdr-cdr-adr-adu-cak-cak-cak-aak-aak-aakakcB-acB-acB-acB-acB-acB-acBcBdgdgbz-gbz-gbE-gbE-gbI-gbI-ecB-abI-gbI-ecB-aar-car-car-car-car-car-car-car-adfdfbl-cbl-cbl-cbl-adf-abI-gbI-gcB-acB-acB-acB-acB-acB-acBcBdg-ado-ado-ado-adg-Z-S,kv-akZlo-gkviY-akv-gkviY-alo-gkv-akZkv-gkkiNkOld-cldkkiNkOkk-ckkkkiNkOld-cldkkiNkOkk-bkv-akjiMkNlc-clckjiMkNkj-ckjkjiMkNlc-clckjiMkNkj-ckjlciiiMlckNjFjblciM-aii-ajb-aiM-alciiiMlckNjFjblciM-aii-ajb-ajR-qjo-ciY-clo-aiujniY-ajniYlo-aiujniM-clc-aiijbiM-ajbiMlc-aiulokjiMkNlc-clckjiMkNkj-ckjkjiMkNlc-clckjiMkNkj-ckjlciiiMlckNjFjblciM-aii-ajb-aiM-alciiiMlckNjFjblciM-aii-ajb-ajR-aiM-clc-aiijbiM-ajbiMlc-aiilciM-clc-aiijbiM-ajbiMlc-aiulodl-ohTixjbhTlcjUjqhTjb-aix-ajq-ajb-ahTixjbhTlcjUjqhTjb-aix-ajq-akg-gkK-dkK-clo-ekK-Z-D,ck-bck-gck-bck-gck-bcX-gck-bck-Ecm-eck-aca-cba-acN-aca-cca-aancNca-cba-acN-aca-cca-aancNcN-cbA-cca-cca-ccN-cbA-cca-cca-abK-eck-cbk-cck-acX-abk-cca-cba-cca-cba-cca-cba-cca-cba-adxcXca-cca-cca-cca-aancNca-cba-acN-aca-cca-aancNcN-cbA-cca-cca-ccN-cbA-cca-cca-abK-aca-cba-cca-cba-adncNca-cba-cca-cba-adxcX!!-gcz-gda-cbN-ccn-ccn-cda-cbN-ccn-ccn-abX-gcx-Z-S,dliY-alo-gdl-akZkv-gdl-akZeq-gdliY-adl-gcX-ccX-ccX-ccX-ccX-cbz-aec-acX-ccX-apm-acW-cby-aeb-acW-ccW-aatebcW-cby-aeb-acW-ccW-aatebeb-cck-ccW-ccW-ceb-cck-ccW-ccW-acz-ecW-cby-ccW-aeb-aby-ccW-cby-ccW-aeb-aby-ccW-cby-ccW-aeb-aby-afceqcW-ccW-ccW-ccW-aatebcW-cby-aeb-acW-ccW-aatebeb-cck-ccW-ccW-ceb-cck-ccW-ccW-acz-acW-cby-ccW-aeb-aby-aeNebcW-cby-ccW-aeb-aby-afceq!!-gdG-geu-ccD-cdp-cdp-ceu-ccD-cdp-cdp-acS-gdE-fjn-dif-Z-G<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#rebirth\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Rebirth)-vdpdododf-gdpdododf-cdu-ccK-ccK-ccK-ccK-ccK-ccK-ccK-ccK-acD-aaX-caX-caX-caX-cak-cak-cak-cak-cbP-cbP-cbP-abP-abPbPcH-acB-acB-acB-acB-acB-acB-acBcBdg-adu-cdr-cdr-cdr-adr-adu-cak-cak-cak-aak-aak-aakakcB-acB-acB-acB-acB-acB-acBcBdgdgbz-gbz-gbE-gbE-gbI-gbI-ecB-abI-gbI-ecB-aar-car-car-car-car-car-car-car-adfdfbl-cbl-cbl-cbl-adf-abI-gbI-gcB-acB-acB-acB-acB-acB-acBcBdg-ado-ado-ado-adg-Z-S,kv-akZlo-gkviY-akv-gkviY-alo-gkv-akZkv-gkkiNkOld-cldkkiNkOkk-ckkkkiNkOld-cldkkiNkOkk-bkv-akjiMkNlc-clckjiMkNkj-ckjkjiMkNlc-clckjiMkNkj-ckjlciiiMlckNjFjblciM-aii-ajb-aiM-alciiiMlckNjFjblciM-aii-ajb-ajR-qjo-ciY-clo-aiujniY-ajniYlo-aiujniM-clc-aiijbiM-ajbiMlc-aiulokjiMkNlc-clckjiMkNkj-ckjkjiMkNlc-clckjiMkNkj-ckjlciiiMlckNjFjblciM-aii-ajb-aiM-alciiiMlckNjFjblciM-aii-ajb-ajR-aiM-clc-aiijbiM-ajbiMlc-aiilciM-clc-aiijbiM-ajbiMlc-aiulodl-ohTixjbhTlcjUjqhTjb-aix-ajq-ajb-ahTixjbhTlcjUjqhTjb-aix-ajq-akg-gkK-dkK-clo-ekK-Z-D,ck-bck-gck-bck-gck-bcX-gck-bck-Ecm-eck-aca-cba-acN-aca-cca-aancNca-cba-acN-aca-cca-aancNcN-cbA-cca-cca-ccN-cbA-cca-cca-abK-eck-cbk-cck-acX-abk-cca-cba-cca-cba-cca-cba-cca-cba-adxcXca-cca-cca-cca-aancNca-cba-acN-aca-cca-aancNcN-cbA-cca-cca-ccN-cbA-cca-cca-abK-aca-cba-cca-cba-adncNca-cba-cca-cba-adxcX!!-gcz-gda-cbN-ccn-ccn-cda-cbN-ccn-ccn-abX-gcx-Z-S,dliY-alo-gdl-akZkv-gdl-akZeq-gdliY-adl-gcX-ccX-ccX-ccX-ccX-cbz-aec-acX-ccX-apm-acW-cby-aeb-acW-ccW-aatebcW-cby-aeb-acW-ccW-aatebeb-cck-ccW-ccW-ceb-cck-ccW-ccW-acz-ecW-cby-ccW-aeb-aby-ccW-cby-ccW-aeb-aby-ccW-cby-ccW-aeb-aby-afceqcW-ccW-ccW-ccW-aatebcW-cby-aeb-acW-ccW-aatebeb-cck-ccW-ccW-ceb-cck-ccW-ccW-acz-acW-cby-ccW-aeb-aby-aeNebcW-cby-ccW-aeb-aby-afceq!!-gdG-geu-ccD-cdp-cdp-ceu-ccD-cdp-cdp-acS-gdE-fjn-dif-Z-G\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"all-i-want\">\n  <h3><a class=\"anchor\" href=\"#all-i-want\" title=\"link to section\">#<\/a>The Offspring \u2014 All I Want<\/h3>\n  \n    <p><p>The classic from Crazy Taxi. Transcribed by me.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(All I Want)du-caa-gac-cac-cac-cac-bcCaa-caa-caa-caa-bcCag-gag-fcCaa-gac-cac-cac-cac-bcCaa-caa-caa-caa-bcCag-gag-fcCcF-acF-acF-acz-acz-acz-caa-caa-caa-caa-bcCag-cag-cag-ecG-adf-Z-Z-Z-Z-Z-q,-dfhfrdIeufhfrdIeufhft-bfhft-aeufhft-bfhftdIeufhfrdI-abScceu-afhfrdI-abScceF-afg-adI-abR-aeu-afg-adI-abR-aeu-afhfrdIeufhfrdIeufhft-bfhft-aeufhft-bfhftdIeufhfrdI-abScceu-afhfrdI-abScceF-afg-adI-abR-aeu-afg-adI-abR-aeu-adIeHfgeHdIeFdJ-cdq-cfhfrdI-abScceu-afhfrdI-abScceF-afg-adI-afg-aeu-afg-adI-abR-aeJbNft-Z-Z-Z-Z-Z-q,cA-aeneadA-acAdadA-acAdadA-acAdadA-acAdadA-acAdadA-acAdadA-acA-abn-ada-adA-acA-abn-aeneadA-acA-abn-ada-adA-acA-abn-aeneadA-acAdadA-acAdadA-acAdadA-acAdadA-acAdadA-acAdadA-acA-abn-ada-adA-acA-abn-aeneadA-acA-abn-ada-adA-acA-abn-aeneacAdjdAdjcAdhcA-ccn-cdA-acA-abn-ada-adA-acA-abn-aeneadA-acA-adA-ada-adA-acA-abn-aeuehdJ-Z-Z-Z-Z-Z-q,-bjxjiiE-akUiaiE-akUjxiy-akOhUiy-akOhUiy-akOhUiy-akUjxjq-aix-ahT-aiaixjq-aix-aia-ajyjjjq-aix-ahT-ajb-ajq-aix-ahT-ajqjbix-akUiaix-akUjxiy-akOhUiy-akOhUiE-akUiaiE-akUjxjq-aix-ahT-aiaixjq-aix-aia-ajyjjjq-aix-ahT-ajb-ajq-aix-ahT-ajqjbkOidiyidkOibkO-ckz-cjq-aix-ahT-aiaixjq-aix-aia-ajyjjjq-aix-ajq-aixhTjq-aix-ahT-ajyjjiH-Z-Z-Z-Z-Z-q<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#all-i-want\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(All I Want)du-caa-gac-cac-cac-cac-bcCaa-caa-caa-caa-bcCag-gag-fcCaa-gac-cac-cac-cac-bcCaa-caa-caa-caa-bcCag-gag-fcCcF-acF-acF-acz-acz-acz-caa-caa-caa-caa-bcCag-cag-cag-ecG-adf-Z-Z-Z-Z-Z-q,-dfhfrdIeufhfrdIeufhft-bfhft-aeufhft-bfhftdIeufhfrdI-abScceu-afhfrdI-abScceF-afg-adI-abR-aeu-afg-adI-abR-aeu-afhfrdIeufhfrdIeufhft-bfhft-aeufhft-bfhftdIeufhfrdI-abScceu-afhfrdI-abScceF-afg-adI-abR-aeu-afg-adI-abR-aeu-adIeHfgeHdIeFdJ-cdq-cfhfrdI-abScceu-afhfrdI-abScceF-afg-adI-afg-aeu-afg-adI-abR-aeJbNft-Z-Z-Z-Z-Z-q,cA-aeneadA-acAdadA-acAdadA-acAdadA-acAdadA-acAdadA-acAdadA-acA-abn-ada-adA-acA-abn-aeneadA-acA-abn-ada-adA-acA-abn-aeneadA-acAdadA-acAdadA-acAdadA-acAdadA-acAdadA-acAdadA-acA-abn-ada-adA-acA-abn-aeneadA-acA-abn-ada-adA-acA-abn-aeneacAdjdAdjcAdhcA-ccn-cdA-acA-abn-ada-adA-acA-abn-aeneadA-acA-adA-ada-adA-acA-abn-aeuehdJ-Z-Z-Z-Z-Z-q,-bjxjiiE-akUiaiE-akUjxiy-akOhUiy-akOhUiy-akOhUiy-akUjxjq-aix-ahT-aiaixjq-aix-aia-ajyjjjq-aix-ahT-ajb-ajq-aix-ahT-ajqjbix-akUiaix-akUjxiy-akOhUiy-akOhUiE-akUiaiE-akUjxjq-aix-ahT-aiaixjq-aix-aia-ajyjjjq-aix-ahT-ajb-ajq-aix-ahT-ajqjbkOidiyidkOibkO-ckz-cjq-aix-ahT-aiaixjq-aix-aia-ajyjjjq-aix-ajq-aixhTjq-aix-ahT-ajyjjiH-Z-Z-Z-Z-Z-q\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"nik-nocturnal-metalcore\">\n  <h3><a class=\"anchor\" href=\"#nik-nocturnal-metalcore\" title=\"link to section\">#<\/a>Nik Nocturnal \u2014 I Made a Metalcore Song in a Flash Game<\/h3>\n  \n    <p><p>From <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=FOTRbzNXROw\">the video<\/a>.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(I Made a Metalcore Song in a Flash Game)du-ccL-acB-aaD-abc-aaD-bcDaJ-cbc-cav-caQ-abP-abp-cbl-cab-bcDbE-bcEby-ccB-acA-aaD-abc-aaD-bcDaJ-cbc-cbs-gbr-ecD-aab-bcDbE-bcEby-ccB-acA-caD-abc-aaD-bcDaJ-cbc-caD-eaf-aaT-ccL-acC-icm-fcFcm-ccF-acF-acd-gcd-ecC-aaS-gaS-ecA-caD-abc-aaD-bcDaJ-cbc-caD-eaf-aaT-ccL-acC-acC-acE-adg-Z-Z-Z-Y,ja-gaa-ceb-ccW-ccD-cev-cec-cev-ciM-alf-aez-ceg-aek-aez-ciM-alc-aaa-ceb-ccW-ccD-ciMixiihT-bat-aiMixjFlc-bpn-aez-ceg-aek-aez-ciM-alc-caa-ceb-ccW-ccD-caa-ccW-cbR-ccD-chU-chU-ald-aab-cab-bckab-ccW-ackcDananiManananixiiananhTanananlc-aaa-aiMaack-aixiiaa-ahZaack-alc-caa-ceb-ccW-ccD-caa-ccW-cbR-ccD-cix-ciM-a!!-Z-Z-Z-W,am-gaa-ccN-adQdDca-bcDbN-cad-ccO-acbbOad-ccO-abA-aad-ccQ-acbbOad-ccO-abA-aaa-ccN-adQdDca-bcDbN-kah-cah-cad-ccQ-acbbOad-ccO-abA-a!!-aaa-ccN-adQdDca-bcDbN-caa-cca-cbn-bcDbN-kak-gak-gajaj-aajajaj-aajajaj-aajajaj-aajac-a!!acbC-cac-a!!acbC-abA-a!!-aaa-ccN-adQdDca-bcDbN-caa-cca-cbn-bcDbN-cbN-caj-Z-Z-Z-Y,eL-gnf-ens-anf-cnn-cjriN-bixiMjqpciMix-blc-cjuiQ-biQiBimiBiQiB-blc-aix-anf-ens-anf-cnn-cif-cjr-ajciNif-ejr-ajuiQ-biQiBimiBiQiB-blc-aix-cnf-ens-anf-cnn-chTiMixlcnc-ans-aiMixjqiMlc-giN-aiy-ajqjbiMixiihTlcckjqjbiMixiihTpm-aananjUanananjFjqananjbanananntneaa-ajUaack-ajFjqaa-aiSaack-aix-cnf-ens-anf-cnn-chTiMixlcnc-ans-aiMixjqiMlc-clc-chT-a!!-Z-Z-Z-W<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#nik-nocturnal-metalcore\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(I Made a Metalcore Song in a Flash Game)du-ccL-acB-aaD-abc-aaD-bcDaJ-cbc-cav-caQ-abP-abp-cbl-cab-bcDbE-bcEby-ccB-acA-aaD-abc-aaD-bcDaJ-cbc-cbs-gbr-ecD-aab-bcDbE-bcEby-ccB-acA-caD-abc-aaD-bcDaJ-cbc-caD-eaf-aaT-ccL-acC-icm-fcFcm-ccF-acF-acd-gcd-ecC-aaS-gaS-ecA-caD-abc-aaD-bcDaJ-cbc-caD-eaf-aaT-ccL-acC-acC-acE-adg-Z-Z-Z-Y,ja-gaa-ceb-ccW-ccD-cev-cec-cev-ciM-alf-aez-ceg-aek-aez-ciM-alc-aaa-ceb-ccW-ccD-ciMixiihT-bat-aiMixjFlc-bpn-aez-ceg-aek-aez-ciM-alc-caa-ceb-ccW-ccD-caa-ccW-cbR-ccD-chU-chU-ald-aab-cab-bckab-ccW-ackcDananiManananixiiananhTanananlc-aaa-aiMaack-aixiiaa-ahZaack-alc-caa-ceb-ccW-ccD-caa-ccW-cbR-ccD-cix-ciM-a!!-Z-Z-Z-W,am-gaa-ccN-adQdDca-bcDbN-cad-ccO-acbbOad-ccO-abA-aad-ccQ-acbbOad-ccO-abA-aaa-ccN-adQdDca-bcDbN-kah-cah-cad-ccQ-acbbOad-ccO-abA-a!!-aaa-ccN-adQdDca-bcDbN-caa-cca-cbn-bcDbN-kak-gak-gajaj-aajajaj-aajajaj-aajajaj-aajac-a!!acbC-cac-a!!acbC-abA-a!!-aaa-ccN-adQdDca-bcDbN-caa-cca-cbn-bcDbN-cbN-caj-Z-Z-Z-Y,eL-gnf-ens-anf-cnn-cjriN-bixiMjqpciMix-blc-cjuiQ-biQiBimiBiQiB-blc-aix-anf-ens-anf-cnn-cif-cjr-ajciNif-ejr-ajuiQ-biQiBimiBiQiB-blc-aix-cnf-ens-anf-cnn-chTiMixlcnc-ans-aiMixjqiMlc-giN-aiy-ajqjbiMixiihTlcckjqjbiMixiihTpm-aananjUanananjFjqananjbanananntneaa-ajUaack-ajFjqaa-aiSaack-aix-cnf-ens-anf-cnn-chTiMixlcnc-ans-aiMixjqiMlc-clc-chT-a!!-Z-Z-Z-W\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"zombie-ballet\">\n  <h3><a class=\"anchor\" href=\"#zombie-ballet\" title=\"link to section\">#<\/a>dkoopaable \u2014 Zombie Ballet<\/h3>\n  \n    <p><p>From <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=sM0KqZTxTTs\">the video<\/a>.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Zombie Ballet)-tdu-cdt-kdu-cdt-kdu-cdt-kdu-cdt-kdu-cdt-gcJ-aak-caO-aaP-aak-cdf-adu-abt-bcBbt-gcG-bczbu-bcBbu-gcG-bcBdf-cdu-cdt-kdu-cdt-Z-kdu-adt-Z-Z-Z-U,kZ-big-biJ-biK-bif-big-biJ-biK-bjVjriNiyiNjrkzhUkfki-fkzhUkOiyhUiNiyjrkfki-fjVjriNiyiNjrkzhUkfki-fkzhUkOiyhUiNiyjrkeki-fmf-ckykNhTkykL-amy-anW-ajxjyiJifmqmrmqmt-bjR-aka-aiDjwka-ajwiDhZ-aiDjwhZ-aiDjwka-aiDjwka-ajwiDhZ-aiDjwhZ-aiDkTkajwiBhZkTkEkRhZkajwiBhZjuiDkRkFky-ajU-cjq-ajU-cjU-cjq-cjq-ciM-cix-bhTkg-fkh-aiZkh-ajSlpjS-ajDlajD-ajokLjojSkijaki-ajTlqjT-ajElbjE-ajpkMjp-ciK-aig-ala-akL-aiZ-bkh-bkh-bjT-fiJke-Z-Z-Z-v,aK-bak-bcK-baK-baX-bak-bbX-baK-bbOeObOeObOeObOeObOcocBcocBdbdBeoeObOeObOeObOeObOeOeodOdBdOdBdbcBbOeObOeObOeObOeObOcocBcocBdbdBeoeObOeObOeObOeObOeOeodOdBdOdBdbcBbOeObOeObOeObOeObW-abS-ccF-cbs-ehF-abS-ccF-cbs-cdF-cbS-ccF-cbs-cdF-cbX-gbx-gak-gbX-fbXbx-gaX-gbV-acv-abv-aaX-caY-aaL-acY-aaL-acL-aay-acycYam-aaZ-aaM-acZ-aaM-acM-aaz-acz-cbX-fbXdk-ecK-bcx-fcxbW-Z-Z-Z-v,iK-bkK-bla-bkK-biZ-bkg-bkh-bjR-bcE-acG-acE-acG-acQcU-fcE-acG-acE-acG-acQcU-fmo-amo-amo-ccQcU-fms-amr-amq-akfkecQcU-fmo-amo-amo-ckh-akajZjXkgmy-anW-ajD-f!!cK-cdP-cbY-cfn-ccK-cdP-cbY-cfn-ccS-gcg-gap-gmm-ekZkKmm-akgkdjCiJifiJiY-biJ-bif-aiJ-fig-biZ-aiK-alp-aiK-ala-aiv-akLlpih-aja-aiL-alq-aiL-alb-aiw-akM-cdY-adF-afw-afw-aeK-beK-bfw-bjT-fbbcQ-Z-Z-Z-v<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#zombie-ballet\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Zombie Ballet)-tdu-cdt-kdu-cdt-kdu-cdt-kdu-cdt-kdu-cdt-gcJ-aak-caO-aaP-aak-cdf-adu-abt-bcBbt-gcG-bczbu-bcBbu-gcG-bcBdf-cdu-cdt-kdu-cdt-Z-kdu-adt-Z-Z-Z-U,kZ-big-biJ-biK-bif-big-biJ-biK-bjVjriNiyiNjrkzhUkfki-fkzhUkOiyhUiNiyjrkfki-fjVjriNiyiNjrkzhUkfki-fkzhUkOiyhUiNiyjrkeki-fmf-ckykNhTkykL-amy-anW-ajxjyiJifmqmrmqmt-bjR-aka-aiDjwka-ajwiDhZ-aiDjwhZ-aiDjwka-aiDjwka-ajwiDhZ-aiDjwhZ-aiDkTkajwiBhZkTkEkRhZkajwiBhZjuiDkRkFky-ajU-cjq-ajU-cjU-cjq-cjq-ciM-cix-bhTkg-fkh-aiZkh-ajSlpjS-ajDlajD-ajokLjojSkijaki-ajTlqjT-ajElbjE-ajpkMjp-ciK-aig-ala-akL-aiZ-bkh-bkh-bjT-fiJke-Z-Z-Z-v,aK-bak-bcK-baK-baX-bak-bbX-baK-bbOeObOeObOeObOeObOcocBcocBdbdBeoeObOeObOeObOeObOeOeodOdBdOdBdbcBbOeObOeObOeObOeObOcocBcocBdbdBeoeObOeObOeObOeObOeOeodOdBdOdBdbcBbOeObOeObOeObOeObW-abS-ccF-cbs-ehF-abS-ccF-cbs-cdF-cbS-ccF-cbs-cdF-cbX-gbx-gak-gbX-fbXbx-gaX-gbV-acv-abv-aaX-caY-aaL-acY-aaL-acL-aay-acycYam-aaZ-aaM-acZ-aaM-acM-aaz-acz-cbX-fbXdk-ecK-bcx-fcxbW-Z-Z-Z-v,iK-bkK-bla-bkK-biZ-bkg-bkh-bjR-bcE-acG-acE-acG-acQcU-fcE-acG-acE-acG-acQcU-fmo-amo-amo-ccQcU-fms-amr-amq-akfkecQcU-fmo-amo-amo-ckh-akajZjXkgmy-anW-ajD-f!!cK-cdP-cbY-cfn-ccK-cdP-cbY-cfn-ccS-gcg-gap-gmm-ekZkKmm-akgkdjCiJifiJiY-biJ-bif-aiJ-fig-biZ-aiK-alp-aiK-ala-aiv-akLlpih-aja-aiL-alq-aiL-alb-aiw-akM-cdY-adF-afw-afw-aeK-beK-bfw-bjT-fbbcQ-Z-Z-Z-v\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"never-back-down\">\n  <h3><a class=\"anchor\" href=\"#never-back-down\" title=\"link to section\">#<\/a>Federico Mondino \u2014 Never Back Down<\/h3>\n  \n    <p><p>From <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=7P4cmKypx6I\">the video<\/a>.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Never Back Down)df-ncz-caa-gaa-gaa-gbj-ccz-ccB-acB-aag-ccB-acB-aag-ccB-acB-aau-gcB-acB-aaa-gaa-gcF-acD-aat-gat-gcG-cag-ccD-adf-ncz-caa-gaa-gat-gat-gdfdo-ado-ado-ado-ado-ado-ado-adf-aaa-gaa-ccB-acB-aat-gat-gat-gat-ccz-ocz-cag-gag-ecD-adf-gdh-Z-Z-X,ap-ndJ-ceu-acW-adI-aiMixeu-acW-adI-adf-aeu-aiMixdI-aiM-aeu-akj-acE-cml-cmk-cml-cmk-cml-cmk-cmk-aiMixpm-ceu-acW-adI-aiMixeu-acW-adI-gkk-cev-cfhiNdJ-aeJ-gmk-cml-eiY-aif-biY-cjCdY-dhT-aiMixhT-aixiMkN-ciMixkNixeu-ccW-cdI-ciMixdIixeJ-peu-acW-adI-ceu-acW-akO-cml-cmk-cml-cmk-cml-cmk-cml-ccS-cif-aiYiJkZ-aiJiYif-aiYiJjC-chT-bix-bjqjUhT-bix-cjqif-geH-Z-Z-X,ak-ncA-cda-aca-acA-adNdAda-aca-acA-acb-ada-adNdAcA-adN-ada-aca-acA-cda-aca-acA-adNdAda-aca-acA-adAdNda-cca-cca-chu-cda-aca-acA-adNdAda-aca-acA-gca-cda-cdAdNcA-adk-gda-aca-acA-adN-a!!-pda-cca-ccA-cdNdAcAdAda-cca-ccA-cdNdAcAdAdk-pda-aca-acA-cda-aca-acA-cdk-ack-acK-adXdKdk-ack-acK-adKdXdk-ack-acK-adXdKdk-ack-acK-c!!-key-cda-adNdAcA-cda-adNdAen-aeNendk-gdj-Z-Z-X,if-beu-acW-adI-ceu-acW-adJ-chT-akj-akN-acWdIhT-akj-akN-akl-ahT-acWdIkN-aix-ahT-akj-akO-chT-akj-akN-aiMixhT-akj-akN-aixiMhT-ccX-ccX-cpm-chT-akj-akN-acWdIhT-akj-akN-aixiMeJ-cdl-cif-cixiMkN-aif-ghT-akj-akN-aiM-akZ-biJ-biJ-akZ-akg-akZ-deu-ccW-cdI-ccW-chU-aiNiyhU-aiyiNkO-ciNiykOiy!!hU-akk-akO-ajVjrhU-akk-akO-akZ-ahT-akj-akN-aiMixhT-akj-akO-cif-akv-akZ-aiYiJif-akv-akZ-aiJiYif-akv-akZ-aiYiJif-akv-akZ-chT-ckN-chT-bixjq-chT-aiM-akN-chT-aiM-ajq-ajUjqif-gid-Z-Z-X<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#never-back-down\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Never Back Down)df-ncz-caa-gaa-gaa-gbj-ccz-ccB-acB-aag-ccB-acB-aag-ccB-acB-aau-gcB-acB-aaa-gaa-gcF-acD-aat-gat-gcG-cag-ccD-adf-ncz-caa-gaa-gat-gat-gdfdo-ado-ado-ado-ado-ado-ado-adf-aaa-gaa-ccB-acB-aat-gat-gat-gat-ccz-ocz-cag-gag-ecD-adf-gdh-Z-Z-X,ap-ndJ-ceu-acW-adI-aiMixeu-acW-adI-adf-aeu-aiMixdI-aiM-aeu-akj-acE-cml-cmk-cml-cmk-cml-cmk-cmk-aiMixpm-ceu-acW-adI-aiMixeu-acW-adI-gkk-cev-cfhiNdJ-aeJ-gmk-cml-eiY-aif-biY-cjCdY-dhT-aiMixhT-aixiMkN-ciMixkNixeu-ccW-cdI-ciMixdIixeJ-peu-acW-adI-ceu-acW-akO-cml-cmk-cml-cmk-cml-cmk-cml-ccS-cif-aiYiJkZ-aiJiYif-aiYiJjC-chT-bix-bjqjUhT-bix-cjqif-geH-Z-Z-X,ak-ncA-cda-aca-acA-adNdAda-aca-acA-acb-ada-adNdAcA-adN-ada-aca-acA-cda-aca-acA-adNdAda-aca-acA-adAdNda-cca-cca-chu-cda-aca-acA-adNdAda-aca-acA-gca-cda-cdAdNcA-adk-gda-aca-acA-adN-a!!-pda-cca-ccA-cdNdAcAdAda-cca-ccA-cdNdAcAdAdk-pda-aca-acA-cda-aca-acA-cdk-ack-acK-adXdKdk-ack-acK-adKdXdk-ack-acK-adXdKdk-ack-acK-c!!-key-cda-adNdAcA-cda-adNdAen-aeNendk-gdj-Z-Z-X,if-beu-acW-adI-ceu-acW-adJ-chT-akj-akN-acWdIhT-akj-akN-akl-ahT-acWdIkN-aix-ahT-akj-akO-chT-akj-akN-aiMixhT-akj-akN-aixiMhT-ccX-ccX-cpm-chT-akj-akN-acWdIhT-akj-akN-aixiMeJ-cdl-cif-cixiMkN-aif-ghT-akj-akN-aiM-akZ-biJ-biJ-akZ-akg-akZ-deu-ccW-cdI-ccW-chU-aiNiyhU-aiyiNkO-ciNiykOiy!!hU-akk-akO-ajVjrhU-akk-akO-akZ-ahT-akj-akN-aiMixhT-akj-akO-cif-akv-akZ-aiYiJif-akv-akZ-aiJiYif-akv-akZ-aiYiJif-akv-akZ-chT-ckN-chT-bixjq-chT-aiM-akN-chT-aiM-ajq-ajUjqif-gid-Z-Z-X\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"give-it-all\">\n  <h3><a class=\"anchor\" href=\"#give-it-all\" title=\"link to section\">#<\/a>Rise Against \u2014 Give It All<\/h3>\n  \n    <p><p>Transcribed by Darver <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.kongregate.com\/forums\/3-general-gaming\/topics\/76438-punk-o-matic-2-songs#posts-1992146\">on Kongregate<\/a>.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Give It All)cX-ccY-ccY-ccY-acA-aau-gau-gau-gau-gaA-gaA-gaA-gaA-gdf-bahau-gau-gau-gau-gaA-gaA-gaA-gaA-edfdfcd-gcd-gcd-gcd-gcd-gcd-gcd-gcd-cdf-caA-gaA-gaA-gaA-gah-cah-cah-cah-cah-cah-cah-cah-cdf-Z-Z-Z-g,jC-aiu-ajb-aiJ-ajC-aiu-ajb-aiJ-aaU-bdIaU-adIeuaU-bdIaU-adIeuaM-bdIaM-adIeuaM-bdIaM-adIeubR-ceu-caM-cdI-cbR-ceu-caM-cdI-caU-caU-bdIaU-adIeuaU-bdIaU-adIeuaN-bdIaN-adIeuaN-bdIaN-adIeubR-ceu-caM-cdI-cbR-ceu-caM-cdI-acgbNaM-cdI-caa-ccg-abN-aaM-cdI-caa-ccg-abN-aaN-cdJ-cab-cbS-abz-aaN-cdJ-cab-can-cbR-ceu-caM-cdI-cbR-ceu-caM-cdI-cjq-cjU-bjbjq-bjbjq-cjq-cjU-bjbjq-bjbjq-cjC-Z-Z-Z-g,cx-acx-acx-acx-acx-acx-acx-acx-aaA-bcAaA-acAdaaA-bcAaA-acAdaaA-bcAaA-acAdaaA-bcAaA-acAdabn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-adacn!!-caA-bcAaA-acAdaaA-bcAaA-acAdaaB-bcAaB-acAdaaB-bcAaB-acAdabn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-abxbkaA-ccA-caa-cbx-abk-aaA-ccA-caa-cbx-abk-aaA-ccA-caa-cbn-aba-aaA-ccA-caa-caj-cbn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-adacnbx-Z-Z-Z-g,kK-akK-akK-akK-akK-akK-akK-akK-aaU-bdIaU-adIeuaU-bdIaU-adIeuaM-bdIaM-adIeuaM-bdIaM-adIeubR-ceu-caM-cdI-cbR-ceu-caM-cdI-gaU-bdIaU-adIeuaU-bdIaU-adIeuaN-bdIaN-adIeuaN-bdIaN-adIeubR-ceu-caM-cdI-cbR-ceu-caM-cdI-acgbNaM-cdI-caa-ccg-abN-aaM-cdI-caa-ccg-abN-aaN-cdJ-cab-cbS-abz-aaN-cdJ-cab-can-cbR-ceu-caM-cdI-cbR-ceu-caM-cdI-cbR-ceu-caM-cdI-cbR-ceu-caM-cdI-ccg-Z-Z-Z-g<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#give-it-all\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Give It All)cX-ccY-ccY-ccY-acA-aau-gau-gau-gau-gaA-gaA-gaA-gaA-gdf-bahau-gau-gau-gau-gaA-gaA-gaA-gaA-edfdfcd-gcd-gcd-gcd-gcd-gcd-gcd-gcd-cdf-caA-gaA-gaA-gaA-gah-cah-cah-cah-cah-cah-cah-cah-cdf-Z-Z-Z-g,jC-aiu-ajb-aiJ-ajC-aiu-ajb-aiJ-aaU-bdIaU-adIeuaU-bdIaU-adIeuaM-bdIaM-adIeuaM-bdIaM-adIeubR-ceu-caM-cdI-cbR-ceu-caM-cdI-caU-caU-bdIaU-adIeuaU-bdIaU-adIeuaN-bdIaN-adIeuaN-bdIaN-adIeubR-ceu-caM-cdI-cbR-ceu-caM-cdI-acgbNaM-cdI-caa-ccg-abN-aaM-cdI-caa-ccg-abN-aaN-cdJ-cab-cbS-abz-aaN-cdJ-cab-can-cbR-ceu-caM-cdI-cbR-ceu-caM-cdI-cjq-cjU-bjbjq-bjbjq-cjq-cjU-bjbjq-bjbjq-cjC-Z-Z-Z-g,cx-acx-acx-acx-acx-acx-acx-acx-aaA-bcAaA-acAdaaA-bcAaA-acAdaaA-bcAaA-acAdaaA-bcAaA-acAdabn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-adacn!!-caA-bcAaA-acAdaaA-bcAaA-acAdaaB-bcAaB-acAdaaB-bcAaB-acAdabn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-abxbkaA-ccA-caa-cbx-abk-aaA-ccA-caa-cbx-abk-aaA-ccA-caa-cbn-aba-aaA-ccA-caa-caj-cbn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-adacnbn-acncAda-aeaeNaA-adAdacA-adacnbx-Z-Z-Z-g,kK-akK-akK-akK-akK-akK-akK-akK-aaU-bdIaU-adIeuaU-bdIaU-adIeuaM-bdIaM-adIeuaM-bdIaM-adIeubR-ceu-caM-cdI-cbR-ceu-caM-cdI-gaU-bdIaU-adIeuaU-bdIaU-adIeuaN-bdIaN-adIeuaN-bdIaN-adIeubR-ceu-caM-cdI-cbR-ceu-caM-cdI-acgbNaM-cdI-caa-ccg-abN-aaM-cdI-caa-ccg-abN-aaN-cdJ-cab-cbS-abz-aaN-cdJ-cab-can-cbR-ceu-caM-cdI-cbR-ceu-caM-cdI-cbR-ceu-caM-cdI-cbR-ceu-caM-cdI-ccg-Z-Z-Z-g\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"boulevard-of-broken-dreams\">\n  <h3><a class=\"anchor\" href=\"#boulevard-of-broken-dreams\" title=\"link to section\">#<\/a>Green Day \u2014 Boulevard of Broken Dreams<\/h3>\n  \n    <p><p>Transcribed by Maximus14014 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=iARHEMFXPAo\">on YouTube<\/a>.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Boulevard of Broken Dreams)-xbX-gbX-gbX-gbX-gbX-gbX-fcIcq-gcq-gcq-gcq-ccI-adncDbX-gbX-gbX-gbX-gbX-gbX-gbX-gbX-gbX-fcBce-gce-gce-gce-ccKcKdi-abX-gbX-ddlcA-ace-gce-gcI!!cI!!ce-ccI!!cI!!ce-ccNcNdi-ocI-ace-gce-gce-gce-ccI-acI-acI-acI-acq-gcq-gcq-gcq-gcq-gcq-ccI-Z-E,au-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-adh-adj-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-aclckdp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-adh-adj-aau-abz-aec-acl-aau-abz-aec-ackcWdp-aby-aeb-aat-adp-aby-aeb-aat-adA!!bJ!!eb-aat-adA!!bJ!!cW-cdh-adj-ock-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-acW-ccW-caIaEdEdAeqemdXdTbNbJapalaIaEdEdAeqemdXdTbNbJapalaIaEdEdAeqemdXdTbNbJapalaIaEdEdAeqemdXdTbJal!!-Z-C,-xax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-ach-acj-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abKbAcn-aba-acN-aan-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-ach-acj-aax-abk-acX-abK-aax-abk-acX-abAcacn-aba-acN-aan-acn-aba-acN-aan-acu!!bh!!cN-aan-acu!!bh!!ca-cch-acj-obA-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-aca-cca-bhFax-acx-acX-acK-abk-aak-aax-acx-acX-acK-abk-aak-aax-acx-acX-acK-abk-aak-aax-acx-acX-acK-abhah!!-Z-C,aI-oaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIiYjnkvjRiYjn-aaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIiYjnkvjRiYjn-aaIiYjnkvjRiYjnckdp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-adh-adj-aaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIiYjnkvjRiYjn-aaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIiYjnkvjRiYjn-aaIiYjnkvjRiYjnckdp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-adh-adj-aaIaIbNbNeqeqczczaIaIbNbNeqeqckcWpmiMjbkjjFiMjb-aiiiMjbkjjFiMjb-aiiiMjbkjjFiMjb-aiiiMjbkjkj-ckr-akt-aaIaIbNbNeqeqczczaIaIbNbNeqeqck-adp-aby-aeb-aat-adp-aby-aeb-aat-apmiMjbkjjFiMjb-aiiiMjbkjkj-cjb-caI-adE-aeq-adX-abN-aap-aaI-adE-aeq-adX-abN-aap-aaI-adE-aeq-adX-abN-aap-aaI-adE-aeq-adX-abJal!!-Z-C<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#boulevard-of-broken-dreams\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Boulevard of Broken Dreams)-xbX-gbX-gbX-gbX-gbX-gbX-fcIcq-gcq-gcq-gcq-ccI-adncDbX-gbX-gbX-gbX-gbX-gbX-gbX-gbX-gbX-fcBce-gce-gce-gce-ccKcKdi-abX-gbX-ddlcA-ace-gce-gcI!!cI!!ce-ccI!!cI!!ce-ccNcNdi-ocI-ace-gce-gce-gce-ccI-acI-acI-acI-acq-gcq-gcq-gcq-gcq-gcq-ccI-Z-E,au-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-adh-adj-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-acl-aau-abz-aec-aclckdp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-adh-adj-aau-abz-aec-acl-aau-abz-aec-ackcWdp-aby-aeb-aat-adp-aby-aeb-aat-adA!!bJ!!eb-aat-adA!!bJ!!cW-cdh-adj-ock-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-acW-ccW-caIaEdEdAeqemdXdTbNbJapalaIaEdEdAeqemdXdTbNbJapalaIaEdEdAeqemdXdTbNbJapalaIaEdEdAeqemdXdTbJal!!-Z-C,-xax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-ach-acj-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abK-aax-abk-acX-abKbAcn-aba-acN-aan-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-ach-acj-aax-abk-acX-abK-aax-abk-acX-abAcacn-aba-acN-aan-acn-aba-acN-aan-acu!!bh!!cN-aan-acu!!bh!!ca-cch-acj-obA-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-acN-aan-acn-aba-aca-cca-bhFax-acx-acX-acK-abk-aak-aax-acx-acX-acK-abk-aak-aax-acx-acX-acK-abk-aak-aax-acx-acX-acK-abhah!!-Z-C,aI-oaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIiYjnkvjRiYjn-aaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIiYjnkvjRiYjn-aaIiYjnkvjRiYjnckdp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-adh-adj-aaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIiYjnkvjRiYjn-aaIaIbNbNeqeqczczaIaIbNbNeqeqczczaIiYjnkvjRiYjn-aaIiYjnkvjRiYjnckdp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-aeb-aat-adp-aby-adh-adj-aaIaIbNbNeqeqczczaIaIbNbNeqeqckcWpmiMjbkjjFiMjb-aiiiMjbkjjFiMjb-aiiiMjbkjjFiMjb-aiiiMjbkjkj-ckr-akt-aaIaIbNbNeqeqczczaIaIbNbNeqeqck-adp-aby-aeb-aat-adp-aby-aeb-aat-apmiMjbkjjFiMjb-aiiiMjbkjkj-cjb-caI-adE-aeq-adX-abN-aap-aaI-adE-aeq-adX-abN-aap-aaI-adE-aeq-adX-abN-aap-aaI-adE-aeq-adX-abJal!!-Z-C\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"basket-case\">\n  <h3><a class=\"anchor\" href=\"#basket-case\" title=\"link to section\">#<\/a>Green Day \u2014 Basket Case<\/h3>\n  \n    <p><p>Transcribed by elpitaz <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=mlF28B0XIno\">on YouTube<\/a>.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Basket Case)-FcV-ccV-ccV-ccV-ccV-ccC-acC-abp-c!!-ecC-aat-gat-gat-gat-ecC-aat-gat-gat-ccC-acC-abp-cbp-cbp-cbp-cbp-acD-a!!-cdfdfdfdf-aat-gat-gat-gat-ecE-aat-gat-gat-ccC-acC-abp-acC-aat-ecM-aat-ecD-aat-ecM-aat-gdfdfcO-adfdfdf-Z-Z-Z-F,ef-aco-ada-abj-abC-aef-aco-cef-aco-ada-abj-abC-aef-acl-cbz-acl-aec-aef-abz-acl-aec-aef-abz-acl-aeqdEcW-aby-ack-aelcudgcuelcudgcueb-ack-acW-abf-aby-aeb-ack-ceb-ack-acW-abf-aby-aeb-ack-cby-ack-aeb-cby-ack-aeb-cby-ack-aeqdEcW-aby-ack-aelcudgcuelcudgcuelcudgcuelcudgcubz-cckckckcx-aeb-ack-acW-abf-aby-aeb-ack-ceb-ack-acW-abf-aby-aeb-ackckckckbC-aco-aef-cbC-aco-aef-cbC-aco-aeqdEcW-aby-ack-aeblccWkjbyebck-aeblccWkjbyebck-aeblccWkjbyebck-aeblccWkjbyebck-abNeqcz-abNeqcz-Z-Z-Z-F,-Z-lcX-ccN-abA-aca-aaN-aba-acN-abA-ccN-abA-aca-aaN-aba-acN-abA-cba-abA-acN-cba-abA-acN-cba-abA-acXcxca-aba-abA-acTbGcgbGcTbGcgbGcTbGcgbGcTbGcgbGba-hcX-abA-aca-aaN-aba-acN-abA-ccN-abA-aca-aaN-aba-acN-abAbAbAbAbc-abC-acP-cbc-abC-acP-cbc-abC-acXcxca-aba-abA-acN-aca-abacNbA-acN-aca-abacNbAbAcN-aca-abacNbA-acNcNca-abacNbA-abkcXbK-abkcXbK-Z-Z-Z-F,-Z-helcudgcuelcudgcueb-ack-acW-abf-aby-aeb-ack-ceb-ack-acW-abf-aby-aeb-ack-cby-ack-aeb-cby-ack-aeb-cby-ack-aeqdEcW-aby-ack-aelcudgcuelcudgcuelcudgcuelcudgcubz-heb-ack-acW-abf-aby-aeb-ack-ceb-ack-acW-abf-aby-aeb-ackckckckbC-aco-aef-cbC-aco-aef-cbC-aco-aeqdEcW-aby-ack-aeblccWkjbyebck-aeblccWkjbyebckckeblccWkjbyebck-aeblccWkjbyebck-abNeqcz-abNczcz-Z-Z-Z-F<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#basket-case\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Basket Case)-FcV-ccV-ccV-ccV-ccV-ccC-acC-abp-c!!-ecC-aat-gat-gat-gat-ecC-aat-gat-gat-ccC-acC-abp-cbp-cbp-cbp-cbp-acD-a!!-cdfdfdfdf-aat-gat-gat-gat-ecE-aat-gat-gat-ccC-acC-abp-acC-aat-ecM-aat-ecD-aat-ecM-aat-gdfdfcO-adfdfdf-Z-Z-Z-F,ef-aco-ada-abj-abC-aef-aco-cef-aco-ada-abj-abC-aef-acl-cbz-acl-aec-aef-abz-acl-aec-aef-abz-acl-aeqdEcW-aby-ack-aelcudgcuelcudgcueb-ack-acW-abf-aby-aeb-ack-ceb-ack-acW-abf-aby-aeb-ack-cby-ack-aeb-cby-ack-aeb-cby-ack-aeqdEcW-aby-ack-aelcudgcuelcudgcuelcudgcuelcudgcubz-cckckckcx-aeb-ack-acW-abf-aby-aeb-ack-ceb-ack-acW-abf-aby-aeb-ackckckckbC-aco-aef-cbC-aco-aef-cbC-aco-aeqdEcW-aby-ack-aeblccWkjbyebck-aeblccWkjbyebck-aeblccWkjbyebck-aeblccWkjbyebck-abNeqcz-abNeqcz-Z-Z-Z-F,-Z-lcX-ccN-abA-aca-aaN-aba-acN-abA-ccN-abA-aca-aaN-aba-acN-abA-cba-abA-acN-cba-abA-acN-cba-abA-acXcxca-aba-abA-acTbGcgbGcTbGcgbGcTbGcgbGcTbGcgbGba-hcX-abA-aca-aaN-aba-acN-abA-ccN-abA-aca-aaN-aba-acN-abAbAbAbAbc-abC-acP-cbc-abC-acP-cbc-abC-acXcxca-aba-abA-acN-aca-abacNbA-acN-aca-abacNbAbAcN-aca-abacNbA-acNcNca-abacNbA-abkcXbK-abkcXbK-Z-Z-Z-F,-Z-helcudgcuelcudgcueb-ack-acW-abf-aby-aeb-ack-ceb-ack-acW-abf-aby-aeb-ack-cby-ack-aeb-cby-ack-aeb-cby-ack-aeqdEcW-aby-ack-aelcudgcuelcudgcuelcudgcuelcudgcubz-heb-ack-acW-abf-aby-aeb-ack-ceb-ack-acW-abf-aby-aeb-ackckckckbC-aco-aef-cbC-aco-aef-cbC-aco-aeqdEcW-aby-ack-aeblccWkjbyebck-aeblccWkjbyebckckeblccWkjbyebck-aeblccWkjbyebck-abNeqcz-abNczcz-Z-Z-Z-F\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"still-waiting\">\n  <h3><a class=\"anchor\" href=\"#still-waiting\" title=\"link to section\">#<\/a>Sum 41 \u2014 Still Waiting<\/h3>\n  \n    <p><p>Transcribed by Deo Frances <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=1xtWmSZF1M8\">on YouTube<\/a>.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Still Waiting)-qdjaD-ecE-aaD-ecD-aaE-gaE-gaE-gaE-fcD-aaD-gaD-ecD-aau-gaE-gaE-gaE-gaE-ecE-aaD-gaD-gaJ-gaJ-ecD-aaD-gaD-ecz-acZ!!cZ!!cZ!!cB-aau-ecF-aau-ecC-aau-gau-ecz-acE-aaD-gaD-ecD-aaD-ecB-aaD-ecC-acK-adf-cdj-Z-Z-Z-F,ev-acX-abg-acE-aev-acX-abg-adJdIdX-aaa-acW-aaa-acWcDaa-acW-aaa-acWcDeH-acw-aeH-abr-aan-acw-abg-acEdTid-ajO-aeH-abr-aeH-acw-abg-acEcD-aeu-acW-abf-adI-aeu-acW-abf-adI!!eu!!cW!!aa!!cWbfeH-acw-aid-abr-aan-acw-aiN-acEdOan-acw-aan-abr-aan-acw-abg-acEdIhT-akj-aiM-ajU-ahT-akj-aiM-ajUkNhTifkj-aiMixhTkNeueJkjkviMixiMjqiM-ahTixiM-ahTixiM-ahTixhT-aiMjqhT-ciM-aix-ane-ciM-ajU-ane-ciM-ajU-ane-ciM-ajU-ane-cbf!!jV-ajU-ahT-akj-aiM-ajU-ahT-akj-aiM-ajU-aiM-ahT-aiM-amJ-aiM-ahT-aiM-akN-ahT-app-cid-Z-Z-Z-F,-qhFaa-aca-aaa-acabNda-aca-ada-acabNac-ahB-aac-adV-adc-ahC-aaO-abOcHac-ahB-aac-aaV-aac-ahB-aaO-abN-baa-aca-aaN-acB-aac-acc-aaP-acC!!!!-gac-ahC-aac-aaV-aac-ahB-aaO-abOcEdc-ahC-aac-aaV-aac-ahC-aaO-abOcAae-acc-aaO-abP-aac-acc-aaP-abPcAacdkcackaOdXbNeXaadkccckaNdXbNeXaa-acacAaa-acacAaa-acacAaa-acfcAab!!cb!!aO!!bO!!db-acb-adO-abO-aaa-aca-agv-cab-aca-aaO-abO-aab-acb-aaO-abO-abN-aaa-aca-aaN-abN-aaa-aca-aaN-abN-aaa-aca-aaN-acA-aab-acb-aaO-acB-adf-a!!-Z-Z-Z-J,-riM-ahT-aiM-akN-aiM-ahT-aiM-akN-aah-acw-aah-aiV-aah-ajN-aiN-ajVdTah-acw-aah-aiV-aah-acw-abg-acEpo-aiM-ahT-aiM-akN-aiM-ahT-aiM-akN!!iM-ahT-aiM-akN-aah-acw-aah-abr-aah-acw-abg-acEdOah-acw-aah-abr-aah-acw-abg-app-aaa-acW-abf-acD-aaa-acW-abf-acDdIaaapcWdlbfbucDcSaaapcWdlbfbucDcSaa-acWdIag-adcdOeu-acWdIeu-acWdIaa!!cW!!bf!!cD!!aa!!cW!!bf!!cD!!aa!!cW!!bf!!cD!!aaeJcWkvbfiYcDkgaaeJcWkvbfiYcE-acD-aaa-acW-abf-acD-aaa-acW-abf-acD-aaa-akj-abf-adI-aaa-acW-abf-adI-aeu-apm-ceH-Z-Z-Z-F<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#still-waiting\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Still Waiting)-qdjaD-ecE-aaD-ecD-aaE-gaE-gaE-gaE-fcD-aaD-gaD-ecD-aau-gaE-gaE-gaE-gaE-ecE-aaD-gaD-gaJ-gaJ-ecD-aaD-gaD-ecz-acZ!!cZ!!cZ!!cB-aau-ecF-aau-ecC-aau-gau-ecz-acE-aaD-gaD-ecD-aaD-ecB-aaD-ecC-acK-adf-cdj-Z-Z-Z-F,ev-acX-abg-acE-aev-acX-abg-adJdIdX-aaa-acW-aaa-acWcDaa-acW-aaa-acWcDeH-acw-aeH-abr-aan-acw-abg-acEdTid-ajO-aeH-abr-aeH-acw-abg-acEcD-aeu-acW-abf-adI-aeu-acW-abf-adI!!eu!!cW!!aa!!cWbfeH-acw-aid-abr-aan-acw-aiN-acEdOan-acw-aan-abr-aan-acw-abg-acEdIhT-akj-aiM-ajU-ahT-akj-aiM-ajUkNhTifkj-aiMixhTkNeueJkjkviMixiMjqiM-ahTixiM-ahTixiM-ahTixhT-aiMjqhT-ciM-aix-ane-ciM-ajU-ane-ciM-ajU-ane-ciM-ajU-ane-cbf!!jV-ajU-ahT-akj-aiM-ajU-ahT-akj-aiM-ajU-aiM-ahT-aiM-amJ-aiM-ahT-aiM-akN-ahT-app-cid-Z-Z-Z-F,-qhFaa-aca-aaa-acabNda-aca-ada-acabNac-ahB-aac-adV-adc-ahC-aaO-abOcHac-ahB-aac-aaV-aac-ahB-aaO-abN-baa-aca-aaN-acB-aac-acc-aaP-acC!!!!-gac-ahC-aac-aaV-aac-ahB-aaO-abOcEdc-ahC-aac-aaV-aac-ahC-aaO-abOcAae-acc-aaO-abP-aac-acc-aaP-abPcAacdkcackaOdXbNeXaadkccckaNdXbNeXaa-acacAaa-acacAaa-acacAaa-acfcAab!!cb!!aO!!bO!!db-acb-adO-abO-aaa-aca-agv-cab-aca-aaO-abO-aab-acb-aaO-abO-abN-aaa-aca-aaN-abN-aaa-aca-aaN-abN-aaa-aca-aaN-acA-aab-acb-aaO-acB-adf-a!!-Z-Z-Z-J,-riM-ahT-aiM-akN-aiM-ahT-aiM-akN-aah-acw-aah-aiV-aah-ajN-aiN-ajVdTah-acw-aah-aiV-aah-acw-abg-acEpo-aiM-ahT-aiM-akN-aiM-ahT-aiM-akN!!iM-ahT-aiM-akN-aah-acw-aah-abr-aah-acw-abg-acEdOah-acw-aah-abr-aah-acw-abg-app-aaa-acW-abf-acD-aaa-acW-abf-acDdIaaapcWdlbfbucDcSaaapcWdlbfbucDcSaa-acWdIag-adcdOeu-acWdIeu-acWdIaa!!cW!!bf!!cD!!aa!!cW!!bf!!cD!!aa!!cW!!bf!!cD!!aaeJcWkvbfiYcDkgaaeJcWkvbfiYcE-acD-aaa-acW-abf-acD-aaa-acW-abf-acD-aaa-akj-abf-adI-aaa-acW-abf-adI-aeu-apm-ceH-Z-Z-Z-F\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"the-kids-arent-alright\">\n  <h3><a class=\"anchor\" href=\"#the-kids-arent-alright\" title=\"link to section\">#<\/a>The Offspring \u2014 The Kids Aren&#x27;t Alright<\/h3>\n  \n    <p><p>Transcribed by jienoroffi <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=UIsew0zdnMY\">on YouTube<\/a>.<\/p>\n<\/p>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(The Kids Aren't Alright)-ldu-ccS-ccS-caL-ecB-aau-cau-cau-ecC-aau-cau-cau-ccE-acC-aaD-caD-caD-caD-acC-aaD-caD-caD-caD-acC-aaw-caw-caw-caw-acC-aaw-caw-caw-caw-acC-aau-cau-cau-ecC-aau-cau-cau-ccE-acC-aaD-caD-caD-caD-acC-aaD-caD-caD-caD-acC-aaw-caw-caw-caw-acC-aaw-caw-caw-caw-acC-aaA-caA-caA-caA-acC-aaA-caA-caA-caA-acC-aaw-caw-caw-caw-acC-aaw-caw-caw-caw-acC-aaL-cdf-Z-Z-Q,jHjG-bfjiy-bkAkz-bjdjc-bjG-ciy-ckz-cjc-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-cck-caM-cdp-cby-cck-caM-cdp-cby-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-cck-caM-cdp-cby-cck-caM-cdp-cby-cck-caM-cdp-cby-cck-caM-cdp-cby-cck-caM-cdp-cby-cck-caM-cdp-cby-ccz-ccx-Z-Z-Q,-BbM-cbA-abKbKaA-aaKaKcn-acxcxba-abkbkbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbK-cbJ-Z-Z-Q,kAkBkmkBkAkBkmkBkmkBlfkBlfkBlfkBkAkBkmkBkAkBkmkBkmkBlfkBlfkBlfiAjR-akvkKiJ-akvkKjnjRkvkKlokKkvkKjR-akvkKiJ-akvkKjnjRkvkKlokKkvkKjG-ciy-ckz-cjc-cjG-ciy-ckz-cjc-cjF-cix-cky-cjb-cjF-cix-cky-cjb-cjR-akvkKiJ-akvkKjnjRkvkKlokKkvkKjR-akvkKiJ-akvkKjnjRkvkKlokKkvkKjG-ciy-ckz-cjc-cjG-ciy-ckz-cjc-cjF-cix-cky-cjb-cjF-cix-cky-cjb-ccz-adl-adE-aeqfvfc-aeq-ajn-ckAkBkmkBkAkBkmkBkmkBlfkBlfkBlfkBkAkBkmkBkAkBkmkBkmkBlfkBlfkBlfiAjF-cix-cky-cjb-cjR-cjP-Z-Z-Q<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#the-kids-arent-alright\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(The Kids Aren't Alright)-ldu-ccS-ccS-caL-ecB-aau-cau-cau-ecC-aau-cau-cau-ccE-acC-aaD-caD-caD-caD-acC-aaD-caD-caD-caD-acC-aaw-caw-caw-caw-acC-aaw-caw-caw-caw-acC-aau-cau-cau-ecC-aau-cau-cau-ccE-acC-aaD-caD-caD-caD-acC-aaD-caD-caD-caD-acC-aaw-caw-caw-caw-acC-aaw-caw-caw-caw-acC-aaA-caA-caA-caA-acC-aaA-caA-caA-caA-acC-aaw-caw-caw-caw-acC-aaw-caw-caw-caw-acC-aaL-cdf-Z-Z-Q,jHjG-bfjiy-bkAkz-bjdjc-bjG-ciy-ckz-cjc-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-cck-caM-cdp-cby-cck-caM-cdp-cby-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-ccl-caN-cdq-cbz-cck-caM-cdp-cby-cck-caM-cdp-cby-cck-caM-cdp-cby-cck-caM-cdp-cby-cck-caM-cdp-cby-cck-caM-cdp-cby-ccz-ccx-Z-Z-Q,-BbM-cbA-abKbKaA-aaKaKcn-acxcxba-abkbkbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbA-caA-ccn-cba-cbK-cbJ-Z-Z-Q,kAkBkmkBkAkBkmkBkmkBlfkBlfkBlfkBkAkBkmkBkAkBkmkBkmkBlfkBlfkBlfiAjR-akvkKiJ-akvkKjnjRkvkKlokKkvkKjR-akvkKiJ-akvkKjnjRkvkKlokKkvkKjG-ciy-ckz-cjc-cjG-ciy-ckz-cjc-cjF-cix-cky-cjb-cjF-cix-cky-cjb-cjR-akvkKiJ-akvkKjnjRkvkKlokKkvkKjR-akvkKiJ-akvkKjnjRkvkKlokKkvkKjG-ciy-ckz-cjc-cjG-ciy-ckz-cjc-cjF-cix-cky-cjb-cjF-cix-cky-cjb-ccz-adl-adE-aeqfvfc-aeq-ajn-ckAkBkmkBkAkBkmkBkmkBlfkBlfkBlfkBkAkBkmkBkAkBkmkBkmkBlfkBlfkBlfiAjF-cix-cky-cjb-cjR-cjP-Z-Z-Q\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n"},{"title":"Built-In Songs","published":"2024-03-18T00:00:00+00:00","updated":"2024-03-18T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/punkomatic\/pom2\/"}},"id":"https:\/\/iliazeus.lol\/punkomatic\/pom2\/","content":"<p>These are all the songs bundled with <a href=\"..\">Punk-o-Matic 2<\/a>, sorted by their order of appearance in-game. They are all titled with fictional, in-universe bands, but are all actually written by <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.evildoggames.com\/\">Evil-Dog<\/a>.<\/p>\n<h2 id=\"unlocked-at-the-start-extra\">Unlocked at the start (\"Extra\")<\/h2>\n<p>These are the songs that are already in your band's \"cover list\" at the start of the game.<\/p>\n<hgroup class=\"punkomatic-song\" id=\"open-wound\">\n  <h3><a class=\"anchor\" href=\"#open-wound\" title=\"link to section\">#<\/a>Chucks Nation \u2014 Open Wound (Extra 1)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Open Wound)cL-ccL-ccL-ccL-ccL-ccL-ccL-ccL-acA-aah-cah-acB-aao-cao-acC-acK-ccK-ccL-ccL-adf-acM-ccM-cai-cai-cdg-acA-aaa-gaa-caf-bcBaa-gaB-ecD-aag-gag-ecB-aag-gag-ccD-acC-adididididg-cdu-ccL-ccL-ccL-ccL-ccL-ccL-ccL-ccL-acC-abI-fambI-fambI-fambI-ecD-aaJ-gaJ-cas-caJ-gaJ-ccB-adh-aag-gag-ecB-aag-gag-ecC-adididididg-Z-Z-Q,cM-ccM-cca-ccM-ccM-ccM-cca-ccM-apm-actbHeDaVca-aixiMctbHeDaVca-aiMixib-cib-cib-ciU-aiH-iig-cnr-cif-apt-aew-acF-abT-cew-acF-abT-cew-acF-abT-cex-acG-abU-abY-aeu-acD-abR-ceu-acD-abR-apm-ahT-aix-akj-ajqixeu-acD-abR-abY-aananananap-gcM-ccM-ccM-ccM-cca-cca-cdR-cdR-cab-cab-cab-cab-ccX-ccX-cbS-cbS-ceu-ceu-ccW-cbX-ceu-ccW-cbR-ceA-aeH-aeu-acD-abR-ceu-acD-abR-apm-ahT-aix-akj-ajqixeu-acD-abR-anc-aananananap-Z-Z-Q,aa-caa-cca-caa-caa-caa-cca-cda-caa-cca-cda-cca-cdk-cdk-cca-cca-ackbxak-fdXck-cak-cck-acf-ada-abN-abn-cda-abN-abn-cda-abN-abn-cdb-abO-abo-aes-ada-abN-abn-cda-abN-abn-cda-abN-abn-cda-abN-abs-aes-aaa-adf-aak-gaa-caa-caa-caa-cca-cca-cbn-cbn-abs-aaa-caa-caa-caa-cca-cca-cbn-cbn-caa-caa-cca-cer-caa-cca-cbn-cae-aajhxda-abN-abn-cda-abN-abn-cda-abN-abn-cda-abN-aen-aes-aaa-adf-aak-Z-Z-Q,ap-cnj-cdl-cnj-cap-cnj-cdl-cnj-cif-ckv-cif-ckv-cnj-gnh-cib-akt-enl-cnk-cnl-cnk-cns-ciMhTixkNns-chT-biMns-ciMhTixkNjUiMjqixhV-ahZ-ajUiMjqixiMhTixkNjUiMjqixhT-cns-ciMhTixkNhT-akN-ahT-ahZ-aididididif-gif-ciY-ciJ-ckZ-ckv-ciY-aiJ-akv-ciY-aiJ-aif-ghU-chU-ckk-ckk-cjr-cjr-chT-cix-ciM-cjv-cjU-ciM-cjq-chY-ahT-ajUiMjqixiMhTixkNjUiMjqixhT-cns-ciMhTixkNnt-ano-ans-ano-aididididif-Z-Z-Q<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#open-wound\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Open Wound)cL-ccL-ccL-ccL-ccL-ccL-ccL-ccL-acA-aah-cah-acB-aao-cao-acC-acK-ccK-ccL-ccL-adf-acM-ccM-cai-cai-cdg-acA-aaa-gaa-caf-bcBaa-gaB-ecD-aag-gag-ecB-aag-gag-ccD-acC-adididididg-cdu-ccL-ccL-ccL-ccL-ccL-ccL-ccL-ccL-acC-abI-fambI-fambI-fambI-ecD-aaJ-gaJ-cas-caJ-gaJ-ccB-adh-aag-gag-ecB-aag-gag-ecC-adididididg-Z-Z-Q,cM-ccM-cca-ccM-ccM-ccM-cca-ccM-apm-actbHeDaVca-aixiMctbHeDaVca-aiMixib-cib-cib-ciU-aiH-iig-cnr-cif-apt-aew-acF-abT-cew-acF-abT-cew-acF-abT-cex-acG-abU-abY-aeu-acD-abR-ceu-acD-abR-apm-ahT-aix-akj-ajqixeu-acD-abR-abY-aananananap-gcM-ccM-ccM-ccM-cca-cca-cdR-cdR-cab-cab-cab-cab-ccX-ccX-cbS-cbS-ceu-ceu-ccW-cbX-ceu-ccW-cbR-ceA-aeH-aeu-acD-abR-ceu-acD-abR-apm-ahT-aix-akj-ajqixeu-acD-abR-anc-aananananap-Z-Z-Q,aa-caa-cca-caa-caa-caa-cca-cda-caa-cca-cda-cca-cdk-cdk-cca-cca-ackbxak-fdXck-cak-cck-acf-ada-abN-abn-cda-abN-abn-cda-abN-abn-cdb-abO-abo-aes-ada-abN-abn-cda-abN-abn-cda-abN-abn-cda-abN-abs-aes-aaa-adf-aak-gaa-caa-caa-caa-cca-cca-cbn-cbn-abs-aaa-caa-caa-caa-cca-cca-cbn-cbn-caa-caa-cca-cer-caa-cca-cbn-cae-aajhxda-abN-abn-cda-abN-abn-cda-abN-abn-cda-abN-aen-aes-aaa-adf-aak-Z-Z-Q,ap-cnj-cdl-cnj-cap-cnj-cdl-cnj-cif-ckv-cif-ckv-cnj-gnh-cib-akt-enl-cnk-cnl-cnk-cns-ciMhTixkNns-chT-biMns-ciMhTixkNjUiMjqixhV-ahZ-ajUiMjqixiMhTixkNjUiMjqixhT-cns-ciMhTixkNhT-akN-ahT-ahZ-aididididif-gif-ciY-ciJ-ckZ-ckv-ciY-aiJ-akv-ciY-aiJ-aif-ghU-chU-ckk-ckk-cjr-cjr-chT-cix-ciM-cjv-cjU-ciM-cjq-chY-ahT-ajUiMjqixiMhTixkNjUiMjqixhT-cns-ciMhTixkNnt-ano-ans-ano-aididididif-Z-Z-Q\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"end-game\">\n  <h3><a class=\"anchor\" href=\"#end-game\" title=\"link to section\">#<\/a>Druox \u2014 End Game (Extra 2)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(End Game)aT-caT-caT-caT-caT-caT-caT-caT-cdf-gdf-gbx-gbx-gaU-caU-caU-caU-aba-abx-gbx-gaU-caU-caU-caU-aba-aba-cba-cbvbv-bbw-cbvbv-bbw-cbv-gbv-gbx-gbx-gdf-gdf-ebtbwcB-aaT-caT-caT-caT-caT-caT-caT-caT-cdf-Z-Z-Z-Z-m,gn-ggn-ggn-ggn-gag-caz-abuczag-caz-abuczbY-cbm-apo-abY-cbm-apr-aaabfaMckkjbfckataabfaMckkjbfpm-abY-cbm-apo-abY-cbm-apr-aaabfaMckkjbfckataabfaMckkjbfpm-aaa-caa-apo-aac-cac-cac-cac-cac-cac-cac-cac-cbY-cbm-apo-abY-cbm-apr-aag-caz-abuczag-caz-abuczpm-agn-ggn-ggn-ggn-gan-Z-Z-Z-Z-m,-pfO-gfO-gak-cax-aaXbKak-cax-aaXbKbs-caS-cbs-caS-cafaSaFbFcfaSbFasafaSaFbFcfaShu-abs-caS-cbs-caS-cafaSaFbFcfaSbFasafaSaFbFcfaShu-aab-cab-ahu-aaa-caa-caa-caa-caa-caa-caa-caa-cbs-caS-cbs-caS-cak-cax-aaXbKak-cax-aaXbKhu-a!!-ofO-gfO-gaj-Z-Z-Z-Z-m,eu-cdI-ceu-cdI-ceu-cdI-ceu-cdI-cag-caz-abicnhY-cin-akleebY-aiTjxbm-aipiTbY-aiTjxbm-aipiaia-cia-adS-aia-cia-ael-abY-aiTjxbm-aipiTbY-aiTjxbm-aipiaia-cia-adS-aia-cia-ael-ahV-chV-apo-aibkcoxlGhX-cibkcoxlGhX-clM-alM-ahX-alO-alM-alF-ahX-alN-abY-aiTjxbm-aipiTbY-aiTjxbm-aipiaag-caz-abicnhY-cin-akleepm-aeu-cdI-ceu-cdI-ceu-cdI-ceu-cdI-cid-Z-Z-Z-Z-m<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#end-game\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(End Game)aT-caT-caT-caT-caT-caT-caT-caT-cdf-gdf-gbx-gbx-gaU-caU-caU-caU-aba-abx-gbx-gaU-caU-caU-caU-aba-aba-cba-cbvbv-bbw-cbvbv-bbw-cbv-gbv-gbx-gbx-gdf-gdf-ebtbwcB-aaT-caT-caT-caT-caT-caT-caT-caT-cdf-Z-Z-Z-Z-m,gn-ggn-ggn-ggn-gag-caz-abuczag-caz-abuczbY-cbm-apo-abY-cbm-apr-aaabfaMckkjbfckataabfaMckkjbfpm-abY-cbm-apo-abY-cbm-apr-aaabfaMckkjbfckataabfaMckkjbfpm-aaa-caa-apo-aac-cac-cac-cac-cac-cac-cac-cac-cbY-cbm-apo-abY-cbm-apr-aag-caz-abuczag-caz-abuczpm-agn-ggn-ggn-ggn-gan-Z-Z-Z-Z-m,-pfO-gfO-gak-cax-aaXbKak-cax-aaXbKbs-caS-cbs-caS-cafaSaFbFcfaSbFasafaSaFbFcfaShu-abs-caS-cbs-caS-cafaSaFbFcfaSbFasafaSaFbFcfaShu-aab-cab-ahu-aaa-caa-caa-caa-caa-caa-caa-caa-cbs-caS-cbs-caS-cak-cax-aaXbKak-cax-aaXbKhu-a!!-ofO-gfO-gaj-Z-Z-Z-Z-m,eu-cdI-ceu-cdI-ceu-cdI-ceu-cdI-cag-caz-abicnhY-cin-akleebY-aiTjxbm-aipiTbY-aiTjxbm-aipiaia-cia-adS-aia-cia-ael-abY-aiTjxbm-aipiTbY-aiTjxbm-aipiaia-cia-adS-aia-cia-ael-ahV-chV-apo-aibkcoxlGhX-cibkcoxlGhX-clM-alM-ahX-alO-alM-alF-ahX-alN-abY-aiTjxbm-aipiTbY-aiTjxbm-aipiaag-caz-abicnhY-cin-akleepm-aeu-cdI-ceu-cdI-ceu-cdI-ceu-cdI-cid-Z-Z-Z-Z-m\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"from-the-heart\">\n  <h3><a class=\"anchor\" href=\"#from-the-heart\" title=\"link to section\">#<\/a>Bored Again \u2014 From The Heart (Extra 3)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(From The Heart)-Bdg-cba-aaD-gaD-eba-aav-cav-cav-cba-bcBaJ-gaJ-ecB-aaJ-gcC-acA-adf-cdf-cdf-cdf-cdf-cco-cco-ccp-caB-bcBaB-gaB-ecB-aaB-fcBaB-caB-bcBaB-caB-bcBaB-caB-bcBaB-caB-aba-acB-acB-acB-acC-acB-acB-acB-acC-acB-acB-acB-acC-adf-edi-Z-Z-Z-Z-o,-aif-ckZ-cjC-ciY-cif-ckZ-cjC-biY-cmY-ahT-akN-aix-ajq-ajq-ajq-aiM-aiP-amT-cmb-giP-aiP-ahT-akN-aix-ajq-ajq-ajq-aiM-aiM-ahT-akN-aix-ajq-ajq-ama-aiY-ciY-ccg-ccS-cdX-cbu-ccg-ccS-cjqixkNjqbf-cbf-cdI-cdI-cbf-cbf-ckN-cmS-ccD-cbf-cdI-cmM-ccD-cbf-abj-adX-adX-adX-adX-abu-abu-abu-abu-aiM-ajq-ajU-aky-akZ-ekX-Z-Z-Z-Z-o,cK-cbX-cbx-caX-ccK-cbX-cbx-caX-caN-acA-cbN-cbn-caN-aaP-acA-cbN-cbn-caP-ccA-cbN-cbn-caN-ccA-cbN-cbn-aenbnaX-caX-cbx-cbX-ccK-caX-cbx-cbX-ccK-caN-caN-ccA-ccA-caN-caN-ccA-ccA-cbN-caN-ccA-ccA-cbN-caN-aaP-acK-acK-acK-acK-aaX-aaX-aaX-aaX-ada-cda-ccK-ecJ-Z-Z-Z-Z-o,-biJ-ciJ-ckKkZ-bkgjC-biJ-ciJ-ckKkZkg-alI-ckN-aix-ajU-aix-aky-akN-ajU-ajt-akN-cix-cjq-cjX-ajt-akN-aix-ajU-aix-aky-akN-ajU-ajq-akN-aix-ajU-aix-amc-ame-akg-clx-clx-clx-clx-clx-clx-clx-clx-ciM-cix-ckN-ckN-ciM-cix-cmR-cmY-ciM-aix-ahT-akN-amT-cmT-ciM-aix-ahT-akN-akN-ahT-aix-aiM-akN-ahT-aix-aiM-ahT-aix-aiM-ajq-adX-amT-cdV-Z-Z-Z-Z-o<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#from-the-heart\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(From The Heart)-Bdg-cba-aaD-gaD-eba-aav-cav-cav-cba-bcBaJ-gaJ-ecB-aaJ-gcC-acA-adf-cdf-cdf-cdf-cdf-cco-cco-ccp-caB-bcBaB-gaB-ecB-aaB-fcBaB-caB-bcBaB-caB-bcBaB-caB-bcBaB-caB-aba-acB-acB-acB-acC-acB-acB-acB-acC-acB-acB-acB-acC-adf-edi-Z-Z-Z-Z-o,-aif-ckZ-cjC-ciY-cif-ckZ-cjC-biY-cmY-ahT-akN-aix-ajq-ajq-ajq-aiM-aiP-amT-cmb-giP-aiP-ahT-akN-aix-ajq-ajq-ajq-aiM-aiM-ahT-akN-aix-ajq-ajq-ama-aiY-ciY-ccg-ccS-cdX-cbu-ccg-ccS-cjqixkNjqbf-cbf-cdI-cdI-cbf-cbf-ckN-cmS-ccD-cbf-cdI-cmM-ccD-cbf-abj-adX-adX-adX-adX-abu-abu-abu-abu-aiM-ajq-ajU-aky-akZ-ekX-Z-Z-Z-Z-o,cK-cbX-cbx-caX-ccK-cbX-cbx-caX-caN-acA-cbN-cbn-caN-aaP-acA-cbN-cbn-caP-ccA-cbN-cbn-caN-ccA-cbN-cbn-aenbnaX-caX-cbx-cbX-ccK-caX-cbx-cbX-ccK-caN-caN-ccA-ccA-caN-caN-ccA-ccA-cbN-caN-ccA-ccA-cbN-caN-aaP-acK-acK-acK-acK-aaX-aaX-aaX-aaX-ada-cda-ccK-ecJ-Z-Z-Z-Z-o,-biJ-ciJ-ckKkZ-bkgjC-biJ-ciJ-ckKkZkg-alI-ckN-aix-ajU-aix-aky-akN-ajU-ajt-akN-cix-cjq-cjX-ajt-akN-aix-ajU-aix-aky-akN-ajU-ajq-akN-aix-ajU-aix-amc-ame-akg-clx-clx-clx-clx-clx-clx-clx-clx-ciM-cix-ckN-ckN-ciM-cix-cmR-cmY-ciM-aix-ahT-akN-amT-cmT-ciM-aix-ahT-akN-akN-ahT-aix-aiM-akN-ahT-aix-aiM-ahT-aix-aiM-ajq-adX-amT-cdV-Z-Z-Z-Z-o\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"shove-yourself-up-your-ass\">\n  <h3><a class=\"anchor\" href=\"#shove-yourself-up-your-ass\" title=\"link to section\">#<\/a>Evil-Dog \u2014 Shove Yourself Up Your Ass! (Extra 4)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Shove Yourself Up Your Ass!)-bdu-ccC-abp-gbp-gau-caB-bcDaJ-gaJ-fcBaJ-ccz-cax-gay-ecC-aaB-bcBdf-acB-aag-cag-cag-cag-acC-adf-cdu-bcBbE-gbE-gby-gby-gaJ-gaJ-ccD-acC-acl-ccl-ccl-ccl-acJ-abU-gcg-gbT-gdg-gdu-cdg-Z-Z-Z-Z-A,bw-gbx-acC-aet-ado-abx-acC-aet-ado-abx-acC-aet-aiO!!bx-acC-aet-ado-abx-acC-aet-ado-abx-acC-aet-ado-abg-cbg-cbi-cee-acZ-abi-ceq-apm-abf-ceb-acW-aiM-ciM-ajqjFjR-ajC-aiY-aiu-acW-ceb-ccW-ceb-aeN-aiM-ciM-ciM-ciM-ajqiMiM-ciM-ciM-ciM-ajqiMiN-ciN-ciN-ciN-ajRjCiY-ciY-ciY-ciY-ajCiYiY-Z-Z-Z-Z-U,aZ-ggH-ggH-gaO-abB-acO-acbhxdN-aeA-acN-aca-aaN-abA-acN-aca-aaN-abA-acN-aca-aaN-caN-caO-ccO-acb-aaO-ccX-aca-aaN-ccN-aca-adN-ccN-aca-aaX-gca-ccN-cca-ccN-adn-aaN-ccN-caN-ccN-caN-ccN-caN-ccN-caN-ccN-caN-ccN-acX-aaX-ccX-caX-ccX-caX-ccX-caX-ccX-gaX-Z-Z-Z-Z-A,-diZ-col-cok-coj-coo-cbg-acl-aec-acZ!!iM-aii-aiM-ajFjqol-coo-coq-cjGjriMiiiY-gos-cos-cos-cor-ciM-akNiMop-cjF-ajqjFor-cbu-fpmlc-aiiiMjF-clckNlciiiM-ajq-ajF-clc-cjF-ajqjFlc-cjF-clc-cjF-ajqjFlc-cjG-cld-cjG-ajrjGld-aloiujR-clo-cjR-ajCjRlo-cjR-clo-cjR-ajCjRlo-cjR-ajCjRiY-Z-Z-Z-Z-A<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#shove-yourself-up-your-ass\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Shove Yourself Up Your Ass!)-bdu-ccC-abp-gbp-gau-caB-bcDaJ-gaJ-fcBaJ-ccz-cax-gay-ecC-aaB-bcBdf-acB-aag-cag-cag-cag-acC-adf-cdu-bcBbE-gbE-gby-gby-gaJ-gaJ-ccD-acC-acl-ccl-ccl-ccl-acJ-abU-gcg-gbT-gdg-gdu-cdg-Z-Z-Z-Z-A,bw-gbx-acC-aet-ado-abx-acC-aet-ado-abx-acC-aet-aiO!!bx-acC-aet-ado-abx-acC-aet-ado-abx-acC-aet-ado-abg-cbg-cbi-cee-acZ-abi-ceq-apm-abf-ceb-acW-aiM-ciM-ajqjFjR-ajC-aiY-aiu-acW-ceb-ccW-ceb-aeN-aiM-ciM-ciM-ciM-ajqiMiM-ciM-ciM-ciM-ajqiMiN-ciN-ciN-ciN-ajRjCiY-ciY-ciY-ciY-ajCiYiY-Z-Z-Z-Z-U,aZ-ggH-ggH-gaO-abB-acO-acbhxdN-aeA-acN-aca-aaN-abA-acN-aca-aaN-abA-acN-aca-aaN-caN-caO-ccO-acb-aaO-ccX-aca-aaN-ccN-aca-adN-ccN-aca-aaX-gca-ccN-cca-ccN-adn-aaN-ccN-caN-ccN-caN-ccN-caN-ccN-caN-ccN-caN-ccN-acX-aaX-ccX-caX-ccX-caX-ccX-caX-ccX-gaX-Z-Z-Z-Z-A,-diZ-col-cok-coj-coo-cbg-acl-aec-acZ!!iM-aii-aiM-ajFjqol-coo-coq-cjGjriMiiiY-gos-cos-cos-cor-ciM-akNiMop-cjF-ajqjFor-cbu-fpmlc-aiiiMjF-clckNlciiiM-ajq-ajF-clc-cjF-ajqjFlc-cjF-clc-cjF-ajqjFlc-cjG-cld-cjG-ajrjGld-aloiujR-clo-cjR-ajCjRlo-cjR-clo-cjR-ajCjRlo-cjR-ajCjRiY-Z-Z-Z-Z-A\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"rebirth\">\n  <h3><a class=\"anchor\" href=\"#rebirth\" title=\"link to section\">#<\/a>The Necromancers \u2014 Rebirth (Extra 5)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Rebirth)-vdpdododf-gdpdododf-cdu-ccK-ccK-ccK-ccK-ccK-ccK-ccK-ccK-acD-aaX-caX-caX-caX-cak-cak-cak-cak-cbP-cbP-cbP-abP-abPbPcH-acB-acB-acB-acB-acB-acB-acBcBdg-adu-cdr-cdr-cdr-adr-adu-cak-cak-cak-aak-aak-aakakcB-acB-acB-acB-acB-acB-acBcBdgdgbz-gbz-gbE-gbE-gbI-gbI-ecB-abI-gbI-ecB-aar-car-car-car-car-car-car-car-adfdfbl-cbl-cbl-cbl-adf-abI-gbI-gcB-acB-acB-acB-acB-acB-acBcBdg-ado-ado-ado-adg-Z-S,kv-akZlo-gkviY-akv-gkviY-alo-gkv-akZkv-gkkiNkOld-cldkkiNkOkk-ckkkkiNkOld-cldkkiNkOkk-bkv-akjiMkNlc-clckjiMkNkj-ckjkjiMkNlc-clckjiMkNkj-ckjlciiiMlckNjFjblciM-aii-ajb-aiM-alciiiMlckNjFjblciM-aii-ajb-ajR-qjo-ciY-clo-aiujniY-ajniYlo-aiujniM-clc-aiijbiM-ajbiMlc-aiulokjiMkNlc-clckjiMkNkj-ckjkjiMkNlc-clckjiMkNkj-ckjlciiiMlckNjFjblciM-aii-ajb-aiM-alciiiMlckNjFjblciM-aii-ajb-ajR-aiM-clc-aiijbiM-ajbiMlc-aiilciM-clc-aiijbiM-ajbiMlc-aiulodl-ohTixjbhTlcjUjqhTjb-aix-ajq-ajb-ahTixjbhTlcjUjqhTjb-aix-ajq-akg-gkK-dkK-clo-ekK-Z-D,ck-bck-gck-bck-gck-bcX-gck-bck-Ecm-eck-aca-cba-acN-aca-cca-aancNca-cba-acN-aca-cca-aancNcN-cbA-cca-cca-ccN-cbA-cca-cca-abK-eck-cbk-cck-acX-abk-cca-cba-cca-cba-cca-cba-cca-cba-adxcXca-cca-cca-cca-aancNca-cba-acN-aca-cca-aancNcN-cbA-cca-cca-ccN-cbA-cca-cca-abK-aca-cba-cca-cba-adncNca-cba-cca-cba-adxcX!!-gcz-gda-cbN-ccn-ccn-cda-cbN-ccn-ccn-abX-gcx-Z-S,dliY-alo-gdl-akZkv-gdl-akZeq-gdliY-adl-gcX-ccX-ccX-ccX-ccX-cbz-aec-acX-ccX-apm-acW-cby-aeb-acW-ccW-aatebcW-cby-aeb-acW-ccW-aatebeb-cck-ccW-ccW-ceb-cck-ccW-ccW-acz-ecW-cby-ccW-aeb-aby-ccW-cby-ccW-aeb-aby-ccW-cby-ccW-aeb-aby-afceqcW-ccW-ccW-ccW-aatebcW-cby-aeb-acW-ccW-aatebeb-cck-ccW-ccW-ceb-cck-ccW-ccW-acz-acW-cby-ccW-aeb-aby-aeNebcW-cby-ccW-aeb-aby-afceq!!-gdG-geu-ccD-cdp-cdp-ceu-ccD-cdp-cdp-acS-gdE-fjn-dif-Z-G<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#rebirth\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Rebirth)-vdpdododf-gdpdododf-cdu-ccK-ccK-ccK-ccK-ccK-ccK-ccK-ccK-acD-aaX-caX-caX-caX-cak-cak-cak-cak-cbP-cbP-cbP-abP-abPbPcH-acB-acB-acB-acB-acB-acB-acBcBdg-adu-cdr-cdr-cdr-adr-adu-cak-cak-cak-aak-aak-aakakcB-acB-acB-acB-acB-acB-acBcBdgdgbz-gbz-gbE-gbE-gbI-gbI-ecB-abI-gbI-ecB-aar-car-car-car-car-car-car-car-adfdfbl-cbl-cbl-cbl-adf-abI-gbI-gcB-acB-acB-acB-acB-acB-acBcBdg-ado-ado-ado-adg-Z-S,kv-akZlo-gkviY-akv-gkviY-alo-gkv-akZkv-gkkiNkOld-cldkkiNkOkk-ckkkkiNkOld-cldkkiNkOkk-bkv-akjiMkNlc-clckjiMkNkj-ckjkjiMkNlc-clckjiMkNkj-ckjlciiiMlckNjFjblciM-aii-ajb-aiM-alciiiMlckNjFjblciM-aii-ajb-ajR-qjo-ciY-clo-aiujniY-ajniYlo-aiujniM-clc-aiijbiM-ajbiMlc-aiulokjiMkNlc-clckjiMkNkj-ckjkjiMkNlc-clckjiMkNkj-ckjlciiiMlckNjFjblciM-aii-ajb-aiM-alciiiMlckNjFjblciM-aii-ajb-ajR-aiM-clc-aiijbiM-ajbiMlc-aiilciM-clc-aiijbiM-ajbiMlc-aiulodl-ohTixjbhTlcjUjqhTjb-aix-ajq-ajb-ahTixjbhTlcjUjqhTjb-aix-ajq-akg-gkK-dkK-clo-ekK-Z-D,ck-bck-gck-bck-gck-bcX-gck-bck-Ecm-eck-aca-cba-acN-aca-cca-aancNca-cba-acN-aca-cca-aancNcN-cbA-cca-cca-ccN-cbA-cca-cca-abK-eck-cbk-cck-acX-abk-cca-cba-cca-cba-cca-cba-cca-cba-adxcXca-cca-cca-cca-aancNca-cba-acN-aca-cca-aancNcN-cbA-cca-cca-ccN-cbA-cca-cca-abK-aca-cba-cca-cba-adncNca-cba-cca-cba-adxcX!!-gcz-gda-cbN-ccn-ccn-cda-cbN-ccn-ccn-abX-gcx-Z-S,dliY-alo-gdl-akZkv-gdl-akZeq-gdliY-adl-gcX-ccX-ccX-ccX-ccX-cbz-aec-acX-ccX-apm-acW-cby-aeb-acW-ccW-aatebcW-cby-aeb-acW-ccW-aatebeb-cck-ccW-ccW-ceb-cck-ccW-ccW-acz-ecW-cby-ccW-aeb-aby-ccW-cby-ccW-aeb-aby-ccW-cby-ccW-aeb-aby-afceqcW-ccW-ccW-ccW-aatebcW-cby-aeb-acW-ccW-aatebeb-cck-ccW-ccW-ceb-cck-ccW-ccW-acz-acW-cby-ccW-aeb-aby-aeNebcW-cby-ccW-aeb-aby-afceq!!-gdG-geu-ccD-cdp-cdp-ceu-ccD-cdp-cdp-acS-gdE-fjn-dif-Z-G\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<h2 id=\"garage\">Garage<\/h2>\n<hgroup class=\"punkomatic-song\" id=\"valedico\">\n  <h3><a class=\"anchor\" href=\"#valedico\" title=\"link to section\">#<\/a>The Screaming Pelicans \u2014 Valedico (Garage 1)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Valedico)-ncKcBaC-gaC-gcN-bcBaE-gaE-ecE-aaE-gaE-ecC-aaE-gaE-ccBcBcC-aat-gat-gat-gat-cat-acB-acj-gcj-cct-ccj-gcj-cct-acKcBbX-gbX-gbX-gbX-ccF-acA-acj-gcj-gcj-gcj-gcr-ccE-adg-Z-Z-Z-Z-m,cW-alc-aby-aii-acW-aeb-adI-aeN-acW-alc-aby-aeN-acW-aeb-adI-aeN-adl-ahK-acX-cdJ-ccX-chI-ceg-ceg-afl-aeg-ceg-akC-aeg-ceg-afl-aeP-ced-apm-acW-alc-aby-aeN-acW-aeb-adI-aeN-acW-alc-aby-aeN-adb-aeg-adN-aeS-adl-ghR-cdl-chI-ged-ceU-ceP-ced-cdr-ccY-ceP-beQed-beedr-beQhR-ccW-alc-aby-aeN-acW-aeb-adI-aeN-acW-alc-aby-aeN-adb-aeg-adN-aeS-add-add-add-adj-Z-Z-Z-Z-m,-ghDck-gca-ccN-adn-aca-ccA-adn-ack-cca-ccA-cca-chj-ccN-adA-acN-adA-acN-adA-acn-ccN-adA-acN-adA-adn-ccN-ahF-aca-ccN-adn-aca-acN-acA-adn-aca-ccN-adn-aca-acN-acA-adn-aca-acQcaca-acQdnca-acQcaca-acQdnca-acQcaca-acQdnca-acQcaca-acQdndn-ccN-ccn-cca-cdn-ccN-ccn-cca-cca-ccN-adn-aca-acN-acA-adn-aca-ccN-adn-aca-acN-acA-adn-acf-acf-acf-acj-Z-Z-Z-Z-m,-djF-aeN-akj-coX-ckj-clc-aii-akj-cpf-bpgkv-coN-apb-aoN-apf-aoN-apb-coP-alolclolciuiiixjblolclolcjnjbixkylolclolciuiiixjboI-coX-ckj-clc-aii-akj-cpf-bpgkj-clc-aii-akj-coX-ckv-koW-ckv-gkx-gij-aik-aij-aikiOij-aik-ald-aleknij-aik-aij-aikiOij-aik-ald-aleknkj-clc-aii-akj-cpf-bpgkj-clc-aii-akj-coX-coM-ckp-akt-Z-Z-Z-Z-m<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#valedico\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Valedico)-ncKcBaC-gaC-gcN-bcBaE-gaE-ecE-aaE-gaE-ecC-aaE-gaE-ccBcBcC-aat-gat-gat-gat-cat-acB-acj-gcj-cct-ccj-gcj-cct-acKcBbX-gbX-gbX-gbX-ccF-acA-acj-gcj-gcj-gcj-gcr-ccE-adg-Z-Z-Z-Z-m,cW-alc-aby-aii-acW-aeb-adI-aeN-acW-alc-aby-aeN-acW-aeb-adI-aeN-adl-ahK-acX-cdJ-ccX-chI-ceg-ceg-afl-aeg-ceg-akC-aeg-ceg-afl-aeP-ced-apm-acW-alc-aby-aeN-acW-aeb-adI-aeN-acW-alc-aby-aeN-adb-aeg-adN-aeS-adl-ghR-cdl-chI-ged-ceU-ceP-ced-cdr-ccY-ceP-beQed-beedr-beQhR-ccW-alc-aby-aeN-acW-aeb-adI-aeN-acW-alc-aby-aeN-adb-aeg-adN-aeS-add-add-add-adj-Z-Z-Z-Z-m,-ghDck-gca-ccN-adn-aca-ccA-adn-ack-cca-ccA-cca-chj-ccN-adA-acN-adA-acN-adA-acn-ccN-adA-acN-adA-adn-ccN-ahF-aca-ccN-adn-aca-acN-acA-adn-aca-ccN-adn-aca-acN-acA-adn-aca-acQcaca-acQdnca-acQcaca-acQdnca-acQcaca-acQdnca-acQcaca-acQdndn-ccN-ccn-cca-cdn-ccN-ccn-cca-cca-ccN-adn-aca-acN-acA-adn-aca-ccN-adn-aca-acN-acA-adn-acf-acf-acf-acj-Z-Z-Z-Z-m,-djF-aeN-akj-coX-ckj-clc-aii-akj-cpf-bpgkv-coN-apb-aoN-apf-aoN-apb-coP-alolclolciuiiixjblolclolcjnjbixkylolclolciuiiixjboI-coX-ckj-clc-aii-akj-cpf-bpgkj-clc-aii-akj-coX-ckv-koW-ckv-gkx-gij-aik-aij-aikiOij-aik-ald-aleknij-aik-aij-aikiOij-aik-ald-aleknkj-clc-aii-akj-cpf-bpgkj-clc-aii-akj-coX-coM-ckp-akt-Z-Z-Z-Z-m\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"no-more-dead\">\n  <h3><a class=\"anchor\" href=\"#no-more-dead\" title=\"link to section\">#<\/a>Status Quo Exile \u2014 No More Dead (Garage 2)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(No More Dead)cK-bcBam-cam-cam-cam-cas-cas-cdf-gdf-ecA-aab-ecB-aab-ecC-aax-gax-caB-cax-gaA-ecA-aaf-cao-adh-aab-ecB-aab-ecC-adh-Z-Z-Z-Z-Z-Z-k,aN-caN-cbS-bcDaN-caN-caN-cbS-bcDbb-gaZ-epm-afg-abRcDfg-abRcDfg-abRcDfg-abRcDcG-cbU-caP-caP-ccG-cbU-cnz-gcH-cbV-ace-afg-abRcDfg-abRcDfg-abRcDfg-abRcDft-Z-Z-Z-Z-Z-Z-k,aA-caA-cbn-bbNaA-caA-caA-cbn-bbNaA-caA-caA-cbn-abnbNdA-abnbNdA-abnbNdA-abnbNdA-abnbNbO-cbo-caB-caB-cbO-cbo-caB-caB-cbP-cep-agx-adA-abnbNdA-abnbNdA-abnbNdA-abnbNdJ-Z-Z-Z-Z-Z-Z-k,pn-cix-cjq-bjUix-cix-cix-cjq-bjUiJ-giH-epo-aaM-ajqjUaM-ajqjUaM-ajqjUaM-ajqjUjW-cjs-ciz-cnC-cjW-cjs-cnC-cnC-cjX-cjt-ajA-aaM-ajqjUaM-ajqjUaM-ajqjUaM-ajqjUaZ-Z-Z-Z-Z-Z-Z-k<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#no-more-dead\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(No More Dead)cK-bcBam-cam-cam-cam-cas-cas-cdf-gdf-ecA-aab-ecB-aab-ecC-aax-gax-caB-cax-gaA-ecA-aaf-cao-adh-aab-ecB-aab-ecC-adh-Z-Z-Z-Z-Z-Z-k,aN-caN-cbS-bcDaN-caN-caN-cbS-bcDbb-gaZ-epm-afg-abRcDfg-abRcDfg-abRcDfg-abRcDcG-cbU-caP-caP-ccG-cbU-cnz-gcH-cbV-ace-afg-abRcDfg-abRcDfg-abRcDfg-abRcDft-Z-Z-Z-Z-Z-Z-k,aA-caA-cbn-bbNaA-caA-caA-cbn-bbNaA-caA-caA-cbn-abnbNdA-abnbNdA-abnbNdA-abnbNdA-abnbNbO-cbo-caB-caB-cbO-cbo-caB-caB-cbP-cep-agx-adA-abnbNdA-abnbNdA-abnbNdA-abnbNdJ-Z-Z-Z-Z-Z-Z-k,pn-cix-cjq-bjUix-cix-cix-cjq-bjUiJ-giH-epo-aaM-ajqjUaM-ajqjUaM-ajqjUaM-ajqjUjW-cjs-ciz-cnC-cjW-cjs-cnC-cnC-cjX-cjt-ajA-aaM-ajqjUaM-ajqjUaM-ajqjUaM-ajqjUaZ-Z-Z-Z-Z-Z-Z-k\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"the-avenger\">\n  <h3><a class=\"anchor\" href=\"#the-avenger\" title=\"link to section\">#<\/a>Toxic Infectors \u2014 The Avenger (Garage 3)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(The Avenger)-hdf-cdg-cdf-cdg-ccb-gcb-gcb-gcb-gaN-gaN-gaN-gaN-gcb-gcb-gcb-gcb-gaV-caV-caV-caV-ccI-acB-adf-acF-aaN-gaN-gaN-gaN-gcb-gcb-gcc-gce-gdi-acT-aaV-caW-caU-bcDba-ccK-ccK-ccK-acK-acKcKcKcEcb-gcb-gcb-gcb-gdf-Z-Z-Z-g,ar-gaiaj-aeDaiaj-aeDaiaj-aeDaiaj-aeDai-cai-cai-cai-caU-caU-cbG-caU-cif-aeDdXiu-aaC-aif-aeDiYiu-aaCcMif-aeDcSkZ-adRiJbubobbaVai-cai-cai-cai-cai-caU-caU-cbG-caU-cif-bdXiu-cif-bdXfe-gid-cif-aeDdXiu-aaC-aif-aeDiYiu-aaCcMif-aeDcSkZ-adRiJbubobbaVai-cai-cai-cai-cai-caU-caU-cbG-caU-cfv-cnf-gmd-ceC-ceC-ceC-ceC-aeC-aeCeCeCeCai-cai-cai-cai-caU-caU-cbG-caU-cap-Z-Z-Z-g,am-gaj-caj-caj-caj-baXagdgagdXagdgagdXagdgagdXagdgagdXaGdGaGeKaGdGaGeKbgegbgeXaG-cfT-cfT-cfT-cfT-cfT-cfT-cfT-cfT-cagdgagdXagdgagdXagdgagdXagdgagdXaGdGaGeKaGdGaGeKbgegbgeXaG-cfT-cfT-cfT-cfT-gdj-cfT-cfT-cfT-cfT-cfT-cfT-cfT-cfT-cagdgagdXagdgagdXagdgagdXagdgagdXaGdGaGeKaGdGaGeKbgegbgeXaG-cdK-cgc-cgc-cgB-cgB-cag-cag-cag-aag-aagagagagagdgagdXagdgagdXagdgagdXagdgagdXaGdGaGeKaGdGaGeKbgegbgeXaG-cak-Z-Z-Z-g,ih-gan-can-can-can-bbuaniaaniYaniaaniYaniaaniYaniaaniYaZiEaZjRaZiEaZjRbLjibLkgjM-biEjn-abHiJjC-act-ajn-abHkgjC-actcMjn-abHifjC-aeDkgiYdfiJfpeC-caniaaniYaniaaniYaniaaniYaniaaniYaZiEaZjRaZiEaZjRbLjibLkgjM-biEjn-biJjC-cjn-biJjE-gjl-cjn-abHiJjC-act-ajn-abHkgjC-actcMjn-abHifjC-aeDkgiYdfiJfpeC-cmZ-cnf-gns-cnB-cnu-cjbjqjbixlE-gmL-cmS-cmc-chTiMjqjUeC-ceC-ceC-aeC-apo-caniaaniYaniaaniYaniaaniYaniaaniYaZiEaZjRaZiEaZjRbLjibLkgjM-biEif-Z-Z-Z-g<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#the-avenger\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(The Avenger)-hdf-cdg-cdf-cdg-ccb-gcb-gcb-gcb-gaN-gaN-gaN-gaN-gcb-gcb-gcb-gcb-gaV-caV-caV-caV-ccI-acB-adf-acF-aaN-gaN-gaN-gaN-gcb-gcb-gcc-gce-gdi-acT-aaV-caW-caU-bcDba-ccK-ccK-ccK-acK-acKcKcKcEcb-gcb-gcb-gcb-gdf-Z-Z-Z-g,ar-gaiaj-aeDaiaj-aeDaiaj-aeDaiaj-aeDai-cai-cai-cai-caU-caU-cbG-caU-cif-aeDdXiu-aaC-aif-aeDiYiu-aaCcMif-aeDcSkZ-adRiJbubobbaVai-cai-cai-cai-cai-caU-caU-cbG-caU-cif-bdXiu-cif-bdXfe-gid-cif-aeDdXiu-aaC-aif-aeDiYiu-aaCcMif-aeDcSkZ-adRiJbubobbaVai-cai-cai-cai-cai-caU-caU-cbG-caU-cfv-cnf-gmd-ceC-ceC-ceC-ceC-aeC-aeCeCeCeCai-cai-cai-cai-caU-caU-cbG-caU-cap-Z-Z-Z-g,am-gaj-caj-caj-caj-baXagdgagdXagdgagdXagdgagdXagdgagdXaGdGaGeKaGdGaGeKbgegbgeXaG-cfT-cfT-cfT-cfT-cfT-cfT-cfT-cfT-cagdgagdXagdgagdXagdgagdXagdgagdXaGdGaGeKaGdGaGeKbgegbgeXaG-cfT-cfT-cfT-cfT-gdj-cfT-cfT-cfT-cfT-cfT-cfT-cfT-cfT-cagdgagdXagdgagdXagdgagdXagdgagdXaGdGaGeKaGdGaGeKbgegbgeXaG-cdK-cgc-cgc-cgB-cgB-cag-cag-cag-aag-aagagagagagdgagdXagdgagdXagdgagdXagdgagdXaGdGaGeKaGdGaGeKbgegbgeXaG-cak-Z-Z-Z-g,ih-gan-can-can-can-bbuaniaaniYaniaaniYaniaaniYaniaaniYaZiEaZjRaZiEaZjRbLjibLkgjM-biEjn-abHiJjC-act-ajn-abHkgjC-actcMjn-abHifjC-aeDkgiYdfiJfpeC-caniaaniYaniaaniYaniaaniYaniaaniYaZiEaZjRaZiEaZjRbLjibLkgjM-biEjn-biJjC-cjn-biJjE-gjl-cjn-abHiJjC-act-ajn-abHkgjC-actcMjn-abHifjC-aeDkgiYdfiJfpeC-cmZ-cnf-gns-cnB-cnu-cjbjqjbixlE-gmL-cmS-cmc-chTiMjqjUeC-ceC-ceC-aeC-apo-caniaaniYaniaaniYaniaaniYaniaaniYaZiEaZjRaZiEaZjRbLjibLkgjM-biEif-Z-Z-Z-g\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"trucido\">\n  <h3><a class=\"anchor\" href=\"#trucido\" title=\"link to section\">#<\/a>Sabog \u2014 Trucido (Garage 4)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Trucido)-acI-acI-acI-acI-acI-acI-acI-acJ-abw-cbx-cbw-cbx-acC-abD-cbD-cbD-gbD-cbE-gcBcBcB-abz-gbz-abz-abz-acC-abz-gbz-bcBbi-acC-acK-ccK-ccI-acI-adh-abz-gbz-abz-abD-cbz-abz-abz-ccB-acB-acB-acD-abw-ecD-adf-Z-Z-Z-Z-Z-B,-idn-gdb-ccr-abm-adb-cco-abm-adl-gdl-coI-cdl-coM-cdd-aei-afm-cjY-cjY-aiQixfl-cfl-aezbWjY-cjY-aiQixfl-cgO-cbb-gkv-caZ-adb-ceg-ceS-aeg-adb-ceS-aeg-adb-aeg-aeS-aeg-apn-cdb-cdb-adbdjdj-Z-Z-Z-Z-Z-B,hDcf-acS-abF-aaS-acf-acS-abF-aaS-acd-cbF-aaS-acd-cbC-aaS-acf-acS-abF-aaS-acf-acS-abF-aaS-acf-acS-abF-aaS-acf-acS-adE-ceS-ceS-adSdAdF-cdF-addeqeS-ceS-adSdAdF-cdF-caK-gck-caAbnhg-cht-cds-acS-acf-cds-acS-acf-acS-ads-acS-acf-ccf-ccf-bhDcj-Z-Z-Z-Z-Z-B,-moT-ckn-coI-ckn-coJ-ckv-coT-ckv-coT-ckv-coT-ckp-apm-aiC-ajvjKkg-amC-amy-ciJ-anx-chXjukg-amC-amy-cnC-cnw-ciJ-cnC-cnB-ciH-aoU-cpg-cjf-aiQ-aiQ-cjf-aiQ-aiR-aiR-ajf-aiQ-aiR-aiS-akn-ckn-aoUoSkt-Z-Z-Z-Z-Z-B<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#trucido\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Trucido)-acI-acI-acI-acI-acI-acI-acI-acJ-abw-cbx-cbw-cbx-acC-abD-cbD-cbD-gbD-cbE-gcBcBcB-abz-gbz-abz-abz-acC-abz-gbz-bcBbi-acC-acK-ccK-ccI-acI-adh-abz-gbz-abz-abD-cbz-abz-abz-ccB-acB-acB-acD-abw-ecD-adf-Z-Z-Z-Z-Z-B,-idn-gdb-ccr-abm-adb-cco-abm-adl-gdl-coI-cdl-coM-cdd-aei-afm-cjY-cjY-aiQixfl-cfl-aezbWjY-cjY-aiQixfl-cgO-cbb-gkv-caZ-adb-ceg-ceS-aeg-adb-ceS-aeg-adb-aeg-aeS-aeg-apn-cdb-cdb-adbdjdj-Z-Z-Z-Z-Z-B,hDcf-acS-abF-aaS-acf-acS-abF-aaS-acd-cbF-aaS-acd-cbC-aaS-acf-acS-abF-aaS-acf-acS-abF-aaS-acf-acS-abF-aaS-acf-acS-adE-ceS-ceS-adSdAdF-cdF-addeqeS-ceS-adSdAdF-cdF-caK-gck-caAbnhg-cht-cds-acS-acf-cds-acS-acf-acS-ads-acS-acf-ccf-ccf-bhDcj-Z-Z-Z-Z-Z-B,-moT-ckn-coI-ckn-coJ-ckv-coT-ckv-coT-ckv-coT-ckp-apm-aiC-ajvjKkg-amC-amy-ciJ-anx-chXjukg-amC-amy-cnC-cnw-ciJ-cnC-cnB-ciH-aoU-cpg-cjf-aiQ-aiQ-cjf-aiQ-aiR-aiR-ajf-aiQ-aiR-aiS-akn-ckn-aoUoSkt-Z-Z-Z-Z-Z-B\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"pick-it-up\">\n  <h3><a class=\"anchor\" href=\"#pick-it-up\" title=\"link to section\">#<\/a>Lemonade Frenzy \u2014 Pick It Up! (Garage 5)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Pick It Up!)-ncJ-abq-gbq-ecB-aau-caw-aaw-aau-caw-aaw-acA-aad-gad-ecA-aag-gag-cae-bcBag-gag-ecC-aaP-gaP-gaP-gaP-ecz-cbq-gbq-ecB-abq-gbq-ecC-adg-Z-Z-Z-Z-Z-o,bxetbxetbxetbx-abxetbxetbxetbx-abxetbxetbxetbx-abxetbxetbxetbx-abx-cet-ado-abx-cet-ado-cbx-cff-cet-cdo-ciM-cii-clc-cko-ciM-cjq-cjF-bjqpl-cbx-cbx-acCdobx-ccC-ado-abx-ccC-ado-abx-ccC-ado-cbxetbxetbxetbx-abxetbxetbxetbx-abxetbxetbxetbx-abxetbxetbxetbx-a!!-Z-Z-Z-Z-Z-o,gP-cgP-aaN-agP-cgP-aaN-agP-cgP-aaN-agP-cgP-aaN-aaO-ccN-aca-aaO-ccN-aca-ahx-adS-cds-ccS-ccf-ahx-adS-cds-ccS-cce-cdN-cdn-ccN-cca-aeFesdP-cdP-cdP-ceC-acc-adP-ceC-acc-adP-ceC-acc-cgP-cgP-aaN-agP-cgP-aaN-agP-cgP-aaN-agP-cgP-aaN-aaW-Z-Z-Z-Z-Z-o,-hja-goh-coh-aok-aoh-coh-aom-abi-cee-acZ-abi-cpg-api-com-com-com-com-com-com-com-com-com-com-com-com-ciY-gja-civ-aiZ-aja-civ-aiZ-aja-civ-aiZ-coh-coh-aok-aoh-coh-aom-aoh-coh-aok-aoh-coh-aom-aiW-Z-Z-Z-Z-Z-o<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#pick-it-up\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Pick It Up!)-ncJ-abq-gbq-ecB-aau-caw-aaw-aau-caw-aaw-acA-aad-gad-ecA-aag-gag-cae-bcBag-gag-ecC-aaP-gaP-gaP-gaP-ecz-cbq-gbq-ecB-abq-gbq-ecC-adg-Z-Z-Z-Z-Z-o,bxetbxetbxetbx-abxetbxetbxetbx-abxetbxetbxetbx-abxetbxetbxetbx-abx-cet-ado-abx-cet-ado-cbx-cff-cet-cdo-ciM-cii-clc-cko-ciM-cjq-cjF-bjqpl-cbx-cbx-acCdobx-ccC-ado-abx-ccC-ado-abx-ccC-ado-cbxetbxetbxetbx-abxetbxetbxetbx-abxetbxetbxetbx-abxetbxetbxetbx-a!!-Z-Z-Z-Z-Z-o,gP-cgP-aaN-agP-cgP-aaN-agP-cgP-aaN-agP-cgP-aaN-aaO-ccN-aca-aaO-ccN-aca-ahx-adS-cds-ccS-ccf-ahx-adS-cds-ccS-cce-cdN-cdn-ccN-cca-aeFesdP-cdP-cdP-ceC-acc-adP-ceC-acc-adP-ceC-acc-cgP-cgP-aaN-agP-cgP-aaN-agP-cgP-aaN-agP-cgP-aaN-aaW-Z-Z-Z-Z-Z-o,-hja-goh-coh-aok-aoh-coh-aom-abi-cee-acZ-abi-cpg-api-com-com-com-com-com-com-com-com-com-com-com-com-ciY-gja-civ-aiZ-aja-civ-aiZ-aja-civ-aiZ-coh-coh-aok-aoh-coh-aom-aoh-coh-aok-aoh-coh-aom-aiW-Z-Z-Z-Z-Z-o\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<h2 id=\"bar\">Bar<\/h2>\n<hgroup class=\"punkomatic-song\" id=\"rolling-with-the-punches\">\n  <h3><a class=\"anchor\" href=\"#rolling-with-the-punches\" title=\"link to section\">#<\/a>Bad Ear \u2014 Rolling With The Punches (Bar 1)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Rolling With The Punches)-hcz-cdg-acF-aaC-gaC-ecF-aaK-gaK-gax-gax-gaB-fcDaB-fcCaP-gaP-ecF-aaS-gaS-ecF-adg-cdu-caP-cdi-acF-aaD-gbL-ecF-adg-cdu-cdf-Z-Z-Z-Z-Z-A,cz-adl-abu-ccz-adldXbu-aczdlck-acW-abf-cck-acWdIbf-apm-acz-gcu-adg-abp-ccu-adg-abp-ccu-adg-abp-ccu-adg-abp-ccu-adg-abp-cck-acW-abf-cck-acWdIbf-ackcWck-acW-abf-cck-acWdIbf-ackcWcl-acX-abg-ccl-acXdJbt-apm-ack-acW-abf-cck-acWdIbf-ackcWcz-cdl-cbs-Z-Z-Z-Z-Z-A,bK-ack-aaX-cbK-ackcKaX-abKckbA-aca-aaN-cbA-acacAaN-ahu-abGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbA-aca-aaN-cbA-acacAaN-abAcabA-aca-aaN-cbA-acacAaN-abAcabA-aca-aaN-cbA-acacAaW-ahu-abA-aca-aaN-cbA-acacAaN-abAcabK-cck-caW-Z-Z-Z-Z-Z-A,pa-cpb-cpa-cpc-cpa-cpb-cpa-cpc-ccz-gjT-goN-coO-coN-coL-coN-coO-coN-coK-cpd-aiNjriQ-aju-apd-aiNjriQ-ajuimpd-aiNjriQ-aju-apd-aiNjriQ-ajuimcz-adl-abu-ccz-adldXpc-cpa-cpb-cpa-cpc-cpa-cpa-cbt-Z-Z-Z-Z-Z-A<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#rolling-with-the-punches\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Rolling With The Punches)-hcz-cdg-acF-aaC-gaC-ecF-aaK-gaK-gax-gax-gaB-fcDaB-fcCaP-gaP-ecF-aaS-gaS-ecF-adg-cdu-caP-cdi-acF-aaD-gbL-ecF-adg-cdu-cdf-Z-Z-Z-Z-Z-A,cz-adl-abu-ccz-adldXbu-aczdlck-acW-abf-cck-acWdIbf-apm-acz-gcu-adg-abp-ccu-adg-abp-ccu-adg-abp-ccu-adg-abp-ccu-adg-abp-cck-acW-abf-cck-acWdIbf-ackcWck-acW-abf-cck-acWdIbf-ackcWcl-acX-abg-ccl-acXdJbt-apm-ack-acW-abf-cck-acWdIbf-ackcWcz-cdl-cbs-Z-Z-Z-Z-Z-A,bK-ack-aaX-cbK-ackcKaX-abKckbA-aca-aaN-cbA-acacAaN-ahu-abGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbGbHcgchaTaUaTaUbA-aca-aaN-cbA-acacAaN-abAcabA-aca-aaN-cbA-acacAaN-abAcabA-aca-aaN-cbA-acacAaW-ahu-abA-aca-aaN-cbA-acacAaN-abAcabK-cck-caW-Z-Z-Z-Z-Z-A,pa-cpb-cpa-cpc-cpa-cpb-cpa-cpc-ccz-gjT-goN-coO-coN-coL-coN-coO-coN-coK-cpd-aiNjriQ-aju-apd-aiNjriQ-ajuimpd-aiNjriQ-aju-apd-aiNjriQ-ajuimcz-adl-abu-ccz-adldXpc-cpa-cpb-cpa-cpc-cpa-cpa-cbt-Z-Z-Z-Z-Z-A\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"another-day\">\n  <h3><a class=\"anchor\" href=\"#another-day\" title=\"link to section\">#<\/a>Zerstoren Sie \u2014 Another Day (Bar 2)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Another Day)-tdu-cdf-cdu-cbM-gbM-gbM-ecA-acK-ccK-ccC-acD-acKcKcB-aaa-gaa-gaa-gaa-ccD-acCcCag-gag-gag-ccD-acF-abc-cbc-cbc-cbc-cbf-cbf-cbf-cbf-ccB-acB-acB-acB-acB-acB-acB-acB-aaa-gaa-gaa-gaa-ccD-acCcCbz-gbz-gbz-gbz-gbL-gbL-gbL-gcz-ccE-acB-acl-gcl-gcl-gcl-ccz-caX-caX-caX-caX-cba-cba-cba-cba-ccDcDcDcDcDcDcDcDcDcDcDcDcDcDcD-acB-acB-acB-acB-acB-acB-acB-acB-adg-Z-s,-bif-aiY-eif-aiY-eiY-bkZ-aiuif-iif-aiY-eif-aiY-eiY-bkZ-aiuif-gbW-ciM-apm-abR-cbf-cbR-cbf-cat-cbf-cbR-cbfcWcDbfbR-cbf-cbR-cbf-cat-cbf-cbV-cbkdbcIbkbV-cbkdbcIbkbR-cbfcWcDbfbR-cbfcWcDbfbR-cbR-cbR-cbR-apn-aby-caM-cby-caM-caa-caM-cby-caMcDckaMby-cby-cby-cby-caM-caa-cby-cby-cby-caM-caa-caM-cby-cck-ccD-cdp-cjn-ojn-ekgjRjn-aiJ-ckgjRjb-cjb-ajUjFjb-aix-cjUjFjb-cjb-ajUjFjb-aix-cjUjFjb-cjb-ajUjFjb-aix-cjUjFjb-cjb-ajUjFjb-aix-cjUjFjn-dlo-Z-n,bx-caX-cbx-caX-cax-caX-cbx-caXckbXaXbx-caX-cbx-caX-cax-caX-cbx-gbx-caNcabNaNbn-caN-cbn-caN-can-caN-cbn-caNcabNaNbn-caN-cbn-caN-can-caN-sbn-caNcabNaNbn-caNcabNaNbn-cbn-cbn-cbn-cba-caA-cba-caA-caa-caA-cba-caAbNbAaAba-cba-cba-cba-caA-caa-cba-cba-cba-caA-caa-caA-cba-cbA-cbN-ccn-sbk-bbkaK-baKcX-bcXbX-acx-aba-caA-ccN-cbN-acn-aba-caA-ccN-cbN-acn-aba-cbA-cbN-ccn-cba-cbA-cbN-ccn-cbk-Z-s,-ajC-bbu-c!!jC-ajCbu-c!!iu-aiukv-aif-acg-hjC-bbu-c!!jC-ajCbu-c!!iu-aiukv-aif-abW-cbW-cbW-cbfcWcDbfjq-ahT-aiM-cjq-ahTjqiM-cii-aiMiikjkNhTiihT-chT-akNiijq-ahT-aiM-cjq-ahTjqiM-cii-aiMiikjkNhTiihW-chY-akSinhW-chY-akSinhT-chT-akNiihT-chT-akNiijq-cjq-ckj-ckj-apm-ajb-alc-aix-cjb-alcjbix-chT-aixhTjUkylchTlc-clc-akyhTjb-cjb-ajUjFjb-cjb-ajUjFix-blchT-alckylc-clc-cjb-cjb-ajUjFjb-cix-ajUjFlc-cjb-aix-alchTixhTjb-ajU-abN-bbNbb-bbbeq-beqcS-adE-abN-bbNbb-bbbeq-beqcS-adE-aby-caM-ceb-ccD-adp-aby-caM-ceb-ccD-adp-aby-cck-ccD-cdp-cby-cck-ccD-cdp-alchTbN-gjn-Z-k<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#another-day\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Another Day)-tdu-cdf-cdu-cbM-gbM-gbM-ecA-acK-ccK-ccC-acD-acKcKcB-aaa-gaa-gaa-gaa-ccD-acCcCag-gag-gag-ccD-acF-abc-cbc-cbc-cbc-cbf-cbf-cbf-cbf-ccB-acB-acB-acB-acB-acB-acB-acB-aaa-gaa-gaa-gaa-ccD-acCcCbz-gbz-gbz-gbz-gbL-gbL-gbL-gcz-ccE-acB-acl-gcl-gcl-gcl-ccz-caX-caX-caX-caX-cba-cba-cba-cba-ccDcDcDcDcDcDcDcDcDcDcDcDcDcDcD-acB-acB-acB-acB-acB-acB-acB-acB-adg-Z-s,-bif-aiY-eif-aiY-eiY-bkZ-aiuif-iif-aiY-eif-aiY-eiY-bkZ-aiuif-gbW-ciM-apm-abR-cbf-cbR-cbf-cat-cbf-cbR-cbfcWcDbfbR-cbf-cbR-cbf-cat-cbf-cbV-cbkdbcIbkbV-cbkdbcIbkbR-cbfcWcDbfbR-cbfcWcDbfbR-cbR-cbR-cbR-apn-aby-caM-cby-caM-caa-caM-cby-caMcDckaMby-cby-cby-cby-caM-caa-cby-cby-cby-caM-caa-caM-cby-cck-ccD-cdp-cjn-ojn-ekgjRjn-aiJ-ckgjRjb-cjb-ajUjFjb-aix-cjUjFjb-cjb-ajUjFjb-aix-cjUjFjb-cjb-ajUjFjb-aix-cjUjFjb-cjb-ajUjFjb-aix-cjUjFjn-dlo-Z-n,bx-caX-cbx-caX-cax-caX-cbx-caXckbXaXbx-caX-cbx-caX-cax-caX-cbx-gbx-caNcabNaNbn-caN-cbn-caN-can-caN-cbn-caNcabNaNbn-caN-cbn-caN-can-caN-sbn-caNcabNaNbn-caNcabNaNbn-cbn-cbn-cbn-cba-caA-cba-caA-caa-caA-cba-caAbNbAaAba-cba-cba-cba-caA-caa-cba-cba-cba-caA-caa-caA-cba-cbA-cbN-ccn-sbk-bbkaK-baKcX-bcXbX-acx-aba-caA-ccN-cbN-acn-aba-caA-ccN-cbN-acn-aba-cbA-cbN-ccn-cba-cbA-cbN-ccn-cbk-Z-s,-ajC-bbu-c!!jC-ajCbu-c!!iu-aiukv-aif-acg-hjC-bbu-c!!jC-ajCbu-c!!iu-aiukv-aif-abW-cbW-cbW-cbfcWcDbfjq-ahT-aiM-cjq-ahTjqiM-cii-aiMiikjkNhTiihT-chT-akNiijq-ahT-aiM-cjq-ahTjqiM-cii-aiMiikjkNhTiihW-chY-akSinhW-chY-akSinhT-chT-akNiihT-chT-akNiijq-cjq-ckj-ckj-apm-ajb-alc-aix-cjb-alcjbix-chT-aixhTjUkylchTlc-clc-akyhTjb-cjb-ajUjFjb-cjb-ajUjFix-blchT-alckylc-clc-cjb-cjb-ajUjFjb-cix-ajUjFlc-cjb-aix-alchTixhTjb-ajU-abN-bbNbb-bbbeq-beqcS-adE-abN-bbNbb-bbbeq-beqcS-adE-aby-caM-ceb-ccD-adp-aby-caM-ceb-ccD-adp-aby-cck-ccD-cdp-cby-cck-ccD-cdp-alchTbN-gjn-Z-k\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"down-the-drain\">\n  <h3><a class=\"anchor\" href=\"#down-the-drain\" title=\"link to section\">#<\/a>Saorio \u2014 Down The Drain (Bar 3)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Down The Drain)cC-aax-caB-cax-caB-aba-aax-caB-bcDaG-caJ-cah-cai-bcBdf-kdu-ccl-gcl-fcDaB-gag-eag-eag-eag-gag-cba-acC-aag-gag-acC-aba-acC-aax-caB-bcDaG-caJ-cah-cai-bcBcL-cdididg-Z-Z-Z-Z-Z-q,er-abg-cec-cbg-cec-aeb-acX-cby-ccX-cbB-ccq-cbE-cdl-ocX-ccX-cbz-cbz-cck-cck-ccW-ckj-aby-cby-ack-cck-acW-cby-cck-cck-ccW-cby-coK-cco-ack-acX-cby-ccX-cbB-ccq-cbE-cdl-ceTdOdj-Z-Z-Z-Z-Z-q,cY-aaN-ccN-caN-ccN-cca-cba-cca-cbb-cbE-cbe-cck-cdxcKck-edxcKck-aca-cca-cba-cba-cbA-cbA-cca-cca-aea-cea-aeA-ceA-aca-cba-cbA-cbA-cca-cba-ceF-cbC-abA-aca-cba-cca-cbb-cbE-cbe-cck-cdrcEcj-Z-Z-Z-Z-Z-q,lp-akNkjkNkjlc-aii-akNkjkNkjjF-ajq-aoR-clc-coR-clc-biiii-clc-akN-akj-ckj-ckj-ckj-ckj-ciikNkjkNkj-ciikNkjkNkN-ciikNkjkNlc-aiMiilckNlc-aiMiilckNii-alckNoE-aoS-coS-coP-coB-coS-coS-coS-aoQ-ajI-ajbiMoR-clc-coR-clc-biiii-clc-akN-akv-cinkSkt-Z-Z-Z-Z-Z-q<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#down-the-drain\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Down The Drain)cC-aax-caB-cax-caB-aba-aax-caB-bcDaG-caJ-cah-cai-bcBdf-kdu-ccl-gcl-fcDaB-gag-eag-eag-eag-gag-cba-acC-aag-gag-acC-aba-acC-aax-caB-bcDaG-caJ-cah-cai-bcBcL-cdididg-Z-Z-Z-Z-Z-q,er-abg-cec-cbg-cec-aeb-acX-cby-ccX-cbB-ccq-cbE-cdl-ocX-ccX-cbz-cbz-cck-cck-ccW-ckj-aby-cby-ack-cck-acW-cby-cck-cck-ccW-cby-coK-cco-ack-acX-cby-ccX-cbB-ccq-cbE-cdl-ceTdOdj-Z-Z-Z-Z-Z-q,cY-aaN-ccN-caN-ccN-cca-cba-cca-cbb-cbE-cbe-cck-cdxcKck-edxcKck-aca-cca-cba-cba-cbA-cbA-cca-cca-aea-cea-aeA-ceA-aca-cba-cbA-cbA-cca-cba-ceF-cbC-abA-aca-cba-cca-cbb-cbE-cbe-cck-cdrcEcj-Z-Z-Z-Z-Z-q,lp-akNkjkNkjlc-aii-akNkjkNkjjF-ajq-aoR-clc-coR-clc-biiii-clc-akN-akj-ckj-ckj-ckj-ckj-ciikNkjkNkj-ciikNkjkNkN-ciikNkjkNlc-aiMiilckNlc-aiMiilckNii-alckNoE-aoS-coS-coP-coB-coS-coS-coS-aoQ-ajI-ajbiMoR-clc-coR-clc-biiii-clc-akN-akv-cinkSkt-Z-Z-Z-Z-Z-q\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"a-reason-to-forgive\">\n  <h3><a class=\"anchor\" href=\"#a-reason-to-forgive\" title=\"link to section\">#<\/a>Killed On Impact \u2014 A Reason To Forgive (Bar 4)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(A Reason To Forgive)-Jdu-cdf-wdu-ccK-ccK-ccK-ccz-acA-acX-ccY-ccX-ccY-acA-aaD-caD-aaDaDaD-caD-acC-aax-cax-cax-cax-acB-aax-gax-ccz-cdf-cdf-acJ-adf-cdu-ccD-acE-acD-acB-abE-gbE-gdh-ccP-ccK-ccL-ccF-acF-acF-acF-acE-acE-acE-adf-acJ-adg-cdg-ccQ-acC-aaB-acF-acr-acr-abG-ccr-acr-abL-cct-act-adg-Z-Z-Z-y,dn-ghe-ghe-ghe-ghe-gdX-chg-ghg-ghg-ghg-ghg-ghu-chx-chu-chv-chu-chx-chu-chv-chm-chm-chm-chm-cec-ccX-cec-ceO-ceq-cdl-cbu-gbf-ack-aeb-apm-apj-cpi-cpl-cpk-cbfcWckebbfcWckbybfcWckebbfcWckbyhr-ahr-ahr-chr-ahr-ahr-abu-chM-ghM-ghM-ghM-ghM-cbu-Z-Z-Z-y,-Z-pgH-ggH-gaX-c!!-ibBcbgV-cgW-cgV-cgW-cgN-cgN-cgN-cgN-ccX-gcN-cdn-ccX-cck-caW-caY-caN-abA-acN-acf-aaN-abA-acN-aca-aaN-abA-acN-aca-a!!-gaNcabAcNaNcabAbagS-agS-agS-cgS-agS-agS-aaX-c!!-ghn-ghn-ghn-ghn-caX-Z-Z-Z-y,dn-gkZ-okQ-cil-akQ-akQ-cil-akQ-ala-koZ-coX-coZ-cow-coZ-coX-coZ-cow-ckZ-koq-cof-coA-cog-coq-cot-cog-coi-cnY-aloiuiY-bjRjC-aiu-ajR-bkZkv-aiYjCjR-bkZkv-bjRiY-gpe-cpg-api-ape-cpf-cpc-cpf-cpf-cpf-aom-apf-cpf-aoC-akQ-ajI-aiP-ckQ-ajI-aiP-aiP-coj-aoi-apb-coj-aoi-aoN-coj-aoi-apb-coj-aoi-apb-coj-aoi-aiN-ciN-Z-Z-Z-u<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#a-reason-to-forgive\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(A Reason To Forgive)-Jdu-cdf-wdu-ccK-ccK-ccK-ccz-acA-acX-ccY-ccX-ccY-acA-aaD-caD-aaDaDaD-caD-acC-aax-cax-cax-cax-acB-aax-gax-ccz-cdf-cdf-acJ-adf-cdu-ccD-acE-acD-acB-abE-gbE-gdh-ccP-ccK-ccL-ccF-acF-acF-acF-acE-acE-acE-adf-acJ-adg-cdg-ccQ-acC-aaB-acF-acr-acr-abG-ccr-acr-abL-cct-act-adg-Z-Z-Z-y,dn-ghe-ghe-ghe-ghe-gdX-chg-ghg-ghg-ghg-ghg-ghu-chx-chu-chv-chu-chx-chu-chv-chm-chm-chm-chm-cec-ccX-cec-ceO-ceq-cdl-cbu-gbf-ack-aeb-apm-apj-cpi-cpl-cpk-cbfcWckebbfcWckbybfcWckebbfcWckbyhr-ahr-ahr-chr-ahr-ahr-abu-chM-ghM-ghM-ghM-ghM-cbu-Z-Z-Z-y,-Z-pgH-ggH-gaX-c!!-ibBcbgV-cgW-cgV-cgW-cgN-cgN-cgN-cgN-ccX-gcN-cdn-ccX-cck-caW-caY-caN-abA-acN-acf-aaN-abA-acN-aca-aaN-abA-acN-aca-a!!-gaNcabAcNaNcabAbagS-agS-agS-cgS-agS-agS-aaX-c!!-ghn-ghn-ghn-ghn-caX-Z-Z-Z-y,dn-gkZ-okQ-cil-akQ-akQ-cil-akQ-ala-koZ-coX-coZ-cow-coZ-coX-coZ-cow-ckZ-koq-cof-coA-cog-coq-cot-cog-coi-cnY-aloiuiY-bjRjC-aiu-ajR-bkZkv-aiYjCjR-bkZkv-bjRiY-gpe-cpg-api-ape-cpf-cpc-cpf-cpf-cpf-aom-apf-cpf-aoC-akQ-ajI-aiP-ckQ-ajI-aiP-aiP-coj-aoi-apb-coj-aoi-aoN-coj-aoi-apb-coj-aoi-apb-coj-aoi-aiN-ciN-Z-Z-Z-u\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"shittin-out-a-helicopter\">\n  <h3><a class=\"anchor\" href=\"#shittin-out-a-helicopter\" title=\"link to section\">#<\/a>The Klaxon Wail \u2014 Shittin Out A Helicopter (Bar 5)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Shittin Out A Helicopter)-hdi-acJ-acQ-bcBaC-gaC-dcBcF-aaL-caL-aba-aaL-caJ-acC-acJ-adf-caE-gaJ-gaE-gaJ-gcJ-aaC-gaC-gaL-gaL-gdf-cdu-caa-gby-dcC-acCdf-ccW-ccW-ccV-acS-aaD-fcBaJ-gaD-fcBaJ-eba-adf-cdu-cdf-Z-Z-Z-Z-E,-hkZ-ciMixhTkNdI-aeu-acD-cdI-aeu-afg-abf-adI-aeu-afg-abf-adI-aeu-afg-abf-adX-edI-aeufgdI-cfg-ceu-cdI-aeufgdI-cfg-ceu-cdV-adL-aex-acG-cdL-aex-afj-abi-adL-aex-acG-cdL-aex-afj-abi-adV-cdY-cfm-ceA-cdO-ceA-cdX-gfg-ceu-apm-adI-aeufgdI-cfg-ceu-cdI-aeufgdI-cfg-ceu-cdV-ddY-bdV-Z-Z-Z-Z-E,-hcK-caN-ccA-ada-abN-ccA-ada-adA-adN-acA-ada-adA-adN-acA-ada-adA-adN-acK-ecA-adadAcA-cdA-cda-ccA-adadAcA-cdA-cda-ccJ-acA-ada-abN-ccA-ada-adA-adN-acA-ada-abN-ccA-ada-adA-adN-acK-ccL-cdE-cde-ccE-cde-ccK-gdA-cda-ahx-acA-adadAcA-cdA-cda-ccA-adadAcA-cdA-cda-ccK-dcL-bcJ-Z-Z-Z-Z-E,lE-glE-clM-clE-glE-clM-alD-alN-alO-alN-alD-alN-alO-ajqixjUjqkZ-emT-cmL-cix-chT-cmU-cmQ-cix-chT-cmU-ajC-aif-amH-ckO-ahU-amO-ckO-ahU-amH-ckO-ahU-amF-ckZiJ-aifkZ-ckN-aix-ahT-ahT-ajq-ajb-ahT-cmT-cmL-cix-chT-cmU-cmQ-cix-chT-cmT-cmL-cix-chT-cmU-cmQ-ckX-Z-Z-Z-Z-E<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#shittin-out-a-helicopter\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Shittin Out A Helicopter)-hdi-acJ-acQ-bcBaC-gaC-dcBcF-aaL-caL-aba-aaL-caJ-acC-acJ-adf-caE-gaJ-gaE-gaJ-gcJ-aaC-gaC-gaL-gaL-gdf-cdu-caa-gby-dcC-acCdf-ccW-ccW-ccV-acS-aaD-fcBaJ-gaD-fcBaJ-eba-adf-cdu-cdf-Z-Z-Z-Z-E,-hkZ-ciMixhTkNdI-aeu-acD-cdI-aeu-afg-abf-adI-aeu-afg-abf-adI-aeu-afg-abf-adX-edI-aeufgdI-cfg-ceu-cdI-aeufgdI-cfg-ceu-cdV-adL-aex-acG-cdL-aex-afj-abi-adL-aex-acG-cdL-aex-afj-abi-adV-cdY-cfm-ceA-cdO-ceA-cdX-gfg-ceu-apm-adI-aeufgdI-cfg-ceu-cdI-aeufgdI-cfg-ceu-cdV-ddY-bdV-Z-Z-Z-Z-E,-hcK-caN-ccA-ada-abN-ccA-ada-adA-adN-acA-ada-adA-adN-acA-ada-adA-adN-acK-ecA-adadAcA-cdA-cda-ccA-adadAcA-cdA-cda-ccJ-acA-ada-abN-ccA-ada-adA-adN-acA-ada-abN-ccA-ada-adA-adN-acK-ccL-cdE-cde-ccE-cde-ccK-gdA-cda-ahx-acA-adadAcA-cdA-cda-ccA-adadAcA-cdA-cda-ccK-dcL-bcJ-Z-Z-Z-Z-E,lE-glE-clM-clE-glE-clM-alD-alN-alO-alN-alD-alN-alO-ajqixjUjqkZ-emT-cmL-cix-chT-cmU-cmQ-cix-chT-cmU-ajC-aif-amH-ckO-ahU-amO-ckO-ahU-amH-ckO-ahU-amF-ckZiJ-aifkZ-ckN-aix-ahT-ahT-ajq-ajb-ahT-cmT-cmL-cix-chT-cmU-cmQ-cix-chT-cmT-cmL-cix-chT-cmU-cmQ-ckX-Z-Z-Z-Z-E\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<h2 id=\"concert-hall\">Concert Hall<\/h2>\n<hgroup class=\"punkomatic-song\" id=\"stand-and-fight\">\n  <h3><a class=\"anchor\" href=\"#stand-and-fight\" title=\"link to section\">#<\/a>Elicium Punks \u2014 Stand and Fight (Concert Hall 1)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Stand and Fight)df-cdf-acJ-adf-acH-adf-acF-acN-ccN-acJ-acN-acH-acN-acF-acK-ccK-ccK-ccK-ccK-ccK-ccK-ccK-ccC-acC-acD-acD-acC-acC-acE-acBdg-gcz-caa-fcBaa-ccC-acD-aag-fcBag-ccC-acD-acv-gcv-ecE-abo-cbo-cbo-cbo-acA-abo-cbo-cbo-cbo-acB-aaG-gaG-gaG-gaJ-gaJ-fcBba-cba-cba-cba-cba-cba-cba-ccz-ccC-acD-acE-adg-Z-Z-Z-H,ap-cbu-cdX-cdX-cap-cbu-cdX-cdX-acS-aae-cae-cae-cae-cae-cae-cdM-ccH-caf-caf-cdN-capbbbucg-gdJ-caa-cdI-bcDcW-adI-aaa-bdIaa-cdI-bcDcW-adI-aaaaMbfbRdb-cdb-cdN-cdN-caa-cdI-ccW-ccW-caa-cdI-ccW-cdI-acD-aad-cad-cad-cad-cbi-cbi-cad-cad-cbi-cbi-baMaa-caa-cbf-cbf-aaM-aaa-caa-cbf-ccD-caa-caa-aan-Z-Z-Z-H,ak-caX-ccK-ccK-cak-caX-ccK-ccK-abX-aaj-gac-cac-cac-cac-ccC-cbP-cad-cad-ccD-cakaKaXbx-gcA-caa-ccA-bbNca-acA-aaa-bcAaa-ccA-bbNca-acA-aaaaAaNbncd-ccd-ccD-ccD-caa-ccA-cca-cca-caa-ccA-cca-ccA-abN-aak-gak-gaX-faKak-gaX-faAaa-caa-caN-caN-aaA-aaa-caa-caN-cbN-caa-caa-aaj-Z-Z-Z-H,if-ciY-ajCiYjC-akgjCiYiJkZiJif-ciY-ajCiYjC-akgjCiYiJkZiJid-gih-gnj-gnk-chWiAiPjtnj-gnk-cifiJiYjC-cjUjqiMixjUjqiMixix-ahTiMix-akN-akjhTkNixhTixiMixix-ahTiMix-akN-akjhTkNixhTixiMjqiM-bixiM-ajqixiM-bixiM-ajqixjU-bjqjU-bjqiM-aix-ajq-aiMixjU-bjqjU-bjqiM-aix-ajq-aiMix!!-gjU-ajq-ajU-aiM-cjq-aiM-aix-ajU-ajq-ajU-aiM-cjq-aiM-aix-ajU-ajq-ajU-aiM-cjq-aiM-aix-ajU-ckN-ajq-aiMixjqiMiMixkNixhT-cjU-ake-Z-Z-Z-H<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#stand-and-fight\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Stand and Fight)df-cdf-acJ-adf-acH-adf-acF-acN-ccN-acJ-acN-acH-acN-acF-acK-ccK-ccK-ccK-ccK-ccK-ccK-ccK-ccC-acC-acD-acD-acC-acC-acE-acBdg-gcz-caa-fcBaa-ccC-acD-aag-fcBag-ccC-acD-acv-gcv-ecE-abo-cbo-cbo-cbo-acA-abo-cbo-cbo-cbo-acB-aaG-gaG-gaG-gaJ-gaJ-fcBba-cba-cba-cba-cba-cba-cba-ccz-ccC-acD-acE-adg-Z-Z-Z-H,ap-cbu-cdX-cdX-cap-cbu-cdX-cdX-acS-aae-cae-cae-cae-cae-cae-cdM-ccH-caf-caf-cdN-capbbbucg-gdJ-caa-cdI-bcDcW-adI-aaa-bdIaa-cdI-bcDcW-adI-aaaaMbfbRdb-cdb-cdN-cdN-caa-cdI-ccW-ccW-caa-cdI-ccW-cdI-acD-aad-cad-cad-cad-cbi-cbi-cad-cad-cbi-cbi-baMaa-caa-cbf-cbf-aaM-aaa-caa-cbf-ccD-caa-caa-aan-Z-Z-Z-H,ak-caX-ccK-ccK-cak-caX-ccK-ccK-abX-aaj-gac-cac-cac-cac-ccC-cbP-cad-cad-ccD-cakaKaXbx-gcA-caa-ccA-bbNca-acA-aaa-bcAaa-ccA-bbNca-acA-aaaaAaNbncd-ccd-ccD-ccD-caa-ccA-cca-cca-caa-ccA-cca-ccA-abN-aak-gak-gaX-faKak-gaX-faAaa-caa-caN-caN-aaA-aaa-caa-caN-cbN-caa-caa-aaj-Z-Z-Z-H,if-ciY-ajCiYjC-akgjCiYiJkZiJif-ciY-ajCiYjC-akgjCiYiJkZiJid-gih-gnj-gnk-chWiAiPjtnj-gnk-cifiJiYjC-cjUjqiMixjUjqiMixix-ahTiMix-akN-akjhTkNixhTixiMixix-ahTiMix-akN-akjhTkNixhTixiMjqiM-bixiM-ajqixiM-bixiM-ajqixjU-bjqjU-bjqiM-aix-ajq-aiMixjU-bjqjU-bjqiM-aix-ajq-aiMix!!-gjU-ajq-ajU-aiM-cjq-aiM-aix-ajU-ajq-ajU-aiM-cjq-aiM-aix-ajU-ajq-ajU-aiM-cjq-aiM-aix-ajU-ckN-ajq-aiMixjqiMiMixkNixhT-cjU-ake-Z-Z-Z-H\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"unbearable-existance\">\n  <h3><a class=\"anchor\" href=\"#unbearable-existance\" title=\"link to section\">#<\/a>Empty Agony \u2014 Unbearable Existance (Concert Hall 2)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Unbearable Existance)df-ecJ-adf-cdf-Hcz-caX-caX-caX-caX-cba-cba-cba-cba-ccj-gcj-gcj-gcq-gdf-cdf-acJ-abT-gbT-cbT-bbTce-gce-gce-gdfcW-bcW-ccW-ccW-ccV-ccV-ccS-ccS-acE-abi-cbi-cbi-cbi-cbi-cbi-cbi-cbi-cbT-gbT-ecJ-adf-Z-Z-Z-N,bN-gap-cbb-vbz-cbz-baNab-caN-bcEby-cby-baMaa-caM-bcDby-cby-baMaa-caM-bcDcD-ccD-caM-caM-caa-caa-caM-caM-cap-cbb-cbN-gap-cbb-cby-cby-caM-caM-caa-caM-cbN-gap-gbN-gap-cbb-cby-caM-caa-caM-cby-caM-caa-caM-cbN-cbb-ccSczbNbbap-abb-abN-Z-Z-Z-N,bk-gak-caK-Dbm-gba-cba-baAaa-caA-bbNba-cba-baAaa-caA-bbNbN-cbN-caA-caA-caa-caa-caA-caA-cak-caK-cbk-gak-caK-cba-cba-caA-caA-caa-caA-cbk-abX-abK-aaK-abX-gbk-abX-abK-aaK-abX-caK-cba-caA-caa-caA-cba-caA-caa-caA-cbk-caK-cbXbKbkaKak-aaK-abk-Z-Z-Z-N,jn-aiJ-ajn-aif-aiJifloifkK-blo-cjblcjUjFjblcjUjFhTixhTkylc-akylcjblcjUjFjblcjUjFhTixhTkylc-akylcjb-cix-cjUjFjbixlchTkylcjb-cix-cjUjFjbixlchTkylcjU-cjU-alcjUjF-cjF-alcjUjb-aix-cjU-aky-alc-ahT-alc-aif-ckK-aif-alo-gif-ckK-aif-alf-clf-ahXlgkB-ckB-algkChT-ajU-aix-ahT-alo-mififlo-gkg-ckg-akgjRjb-cix-cjUjFjbixjUjFjUjF-cjF-cjFjU-cjU-clo-glq-glo-Z-Z-Z-N<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#unbearable-existance\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Unbearable Existance)df-ecJ-adf-cdf-Hcz-caX-caX-caX-caX-cba-cba-cba-cba-ccj-gcj-gcj-gcq-gdf-cdf-acJ-abT-gbT-cbT-bbTce-gce-gce-gdfcW-bcW-ccW-ccW-ccV-ccV-ccS-ccS-acE-abi-cbi-cbi-cbi-cbi-cbi-cbi-cbi-cbT-gbT-ecJ-adf-Z-Z-Z-N,bN-gap-cbb-vbz-cbz-baNab-caN-bcEby-cby-baMaa-caM-bcDby-cby-baMaa-caM-bcDcD-ccD-caM-caM-caa-caa-caM-caM-cap-cbb-cbN-gap-cbb-cby-cby-caM-caM-caa-caM-cbN-gap-gbN-gap-cbb-cby-caM-caa-caM-cby-caM-caa-caM-cbN-cbb-ccSczbNbbap-abb-abN-Z-Z-Z-N,bk-gak-caK-Dbm-gba-cba-baAaa-caA-bbNba-cba-baAaa-caA-bbNbN-cbN-caA-caA-caa-caa-caA-caA-cak-caK-cbk-gak-caK-cba-cba-caA-caA-caa-caA-cbk-abX-abK-aaK-abX-gbk-abX-abK-aaK-abX-caK-cba-caA-caa-caA-cba-caA-caa-caA-cbk-caK-cbXbKbkaKak-aaK-abk-Z-Z-Z-N,jn-aiJ-ajn-aif-aiJifloifkK-blo-cjblcjUjFjblcjUjFhTixhTkylc-akylcjblcjUjFjblcjUjFhTixhTkylc-akylcjb-cix-cjUjFjbixlchTkylcjb-cix-cjUjFjbixlchTkylcjU-cjU-alcjUjF-cjF-alcjUjb-aix-cjU-aky-alc-ahT-alc-aif-ckK-aif-alo-gif-ckK-aif-alf-clf-ahXlgkB-ckB-algkChT-ajU-aix-ahT-alo-mififlo-gkg-ckg-akgjRjb-cix-cjUjFjbixjUjFjUjF-cjF-cjFjU-cjU-clo-glq-glo-Z-Z-Z-N\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"now-is-here\">\n  <h3><a class=\"anchor\" href=\"#now-is-here\" title=\"link to section\">#<\/a>Chucks Nation \u2014 Now Is Here (Concert Hall 3)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Now Is Here)cQ-ccQ-ccQ-ccQ-bcDbC-gbC-cbE-cbD-bcDbz-gbE-cbC-acC-acJ-aax-gax-ecA-aab-cag-cab-cag-acC-abC-cbD-cbC-cbE-cbC-cbD-cbC-cbE-acD-abL-ecC-abL-bcDdf-Z-Z-Z-Z-Z-W,-lkw-ciY-ciu-cjLjwiSiooo-cbs-ceh-cdc-ceh-ceT-cfa-aiY-aiu-aeq-adl-aiY-aiu-aeq-acXcWbk-aay-aeb-acW-abk-aay-aeb-apm-aoB-coA-coB-coA-coB-coA-coB-coA-ckN-ckj-coA-ciY-Z-Z-Z-Z-Z-W,dS-cds-ccS-ccf-cdS-cds-ccS-ccf-cdSeFdscFcR-cce-ccR-cdr-cdw-aaN-aan-acN-aca-aaN-aan-acN-aca-aaQ-aaq-acN-aca-aaQ-aaq-acN-aca-adP-cdp-ccP-ccc-cdP-cdp-ccP-ccc-cdN-cdn-ccN-cck-Z-Z-Z-Z-Z-W,om-com-com-com-com-com-com-com-ciW-clciiiMjFko-clcjFjqiMin-apm-ais-aoy-coy-coy-coy-coy-coy-coy-coy-com-com-com-com-com-com-com-com-cbh-cav-ced-ckv-Z-Z-Z-Z-Z-W<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#now-is-here\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Now Is Here)cQ-ccQ-ccQ-ccQ-bcDbC-gbC-cbE-cbD-bcDbz-gbE-cbC-acC-acJ-aax-gax-ecA-aab-cag-cab-cag-acC-abC-cbD-cbC-cbE-cbC-cbD-cbC-cbE-acD-abL-ecC-abL-bcDdf-Z-Z-Z-Z-Z-W,-lkw-ciY-ciu-cjLjwiSiooo-cbs-ceh-cdc-ceh-ceT-cfa-aiY-aiu-aeq-adl-aiY-aiu-aeq-acXcWbk-aay-aeb-acW-abk-aay-aeb-apm-aoB-coA-coB-coA-coB-coA-coB-coA-ckN-ckj-coA-ciY-Z-Z-Z-Z-Z-W,dS-cds-ccS-ccf-cdS-cds-ccS-ccf-cdSeFdscFcR-cce-ccR-cdr-cdw-aaN-aan-acN-aca-aaN-aan-acN-aca-aaQ-aaq-acN-aca-aaQ-aaq-acN-aca-adP-cdp-ccP-ccc-cdP-cdp-ccP-ccc-cdN-cdn-ccN-cck-Z-Z-Z-Z-Z-W,om-com-com-com-com-com-com-com-ciW-clciiiMjFko-clcjFjqiMin-apm-ais-aoy-coy-coy-coy-coy-coy-coy-coy-com-com-com-com-com-com-com-com-cbh-cav-ced-ckv-Z-Z-Z-Z-Z-W\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"marching-to-war\">\n  <h3><a class=\"anchor\" href=\"#marching-to-war\" title=\"link to section\">#<\/a>The Nuclear Rebellion \u2014 Marching To War (Concert Hall 4)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Marching To War)aX-caX-caX-caX-cbx-gby-ecI-aar-car-car-car-acC-aaa-aaa-caa-caa-aaa-caa-acB-aaf-cae-bcDaa-aaa-caa-caa-aaa-caa-acC-adf-ecJ-adg-cdu-ccL-ccz-cag-gag-gag-gag-bcBdfdgdgdg-Z-Z-Z-Z-Z-B,iJ-ciY-cif-ciY-bpmix-ciM-chT-ciM-apm-acQ-gcU-gcJbXbl-cbl-ccJbXbl-cbl-cbY-cbi-bbfcJbXbl-cbl-ccJbXbl-cbl-ccg-gbu-giJ-aif-akN-aky-anb-cnb-bjUnb-bkNhTixiMjUnb-cnb-bjUnb-bkNifiJiYkg-Z-Z-Z-Z-Z-B,bP-cbP-cbP-caP-baUeS-ceS-ceS-cdS-adU-abP-cbP-cbP-ceP-cbRbraR-caR-cbRbraR-caR-cbs-cdN-cbRbraR-caR-cbRbraR-caR-cep-cdP-adC-adP-cdP-ceP-cbP-bhCaa-ccA-cca-cbn-caa-ccA-cca-cbxbxbxbx-Z-Z-Z-Z-Z-B,mZ-cmZ-cmZ-cmZ-biUmZ-cmZ-cmZ-cmZ-aiU-ake-gki-gmy-ckSkDlH-cmy-cjUjqlF-cjqjUkykNkNhTixiMmy-ckSkDlH-cmy-cjUjqlF-cjC-giY-ckK-akZ-acS-ccE-bcDaa-cdI-ccW-cbR-caa-cdI-ccW-ccgcgcgcg-Z-Z-Z-Z-Z-B<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#marching-to-war\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Marching To War)aX-caX-caX-caX-cbx-gby-ecI-aar-car-car-car-acC-aaa-aaa-caa-caa-aaa-caa-acB-aaf-cae-bcDaa-aaa-caa-caa-aaa-caa-acC-adf-ecJ-adg-cdu-ccL-ccz-cag-gag-gag-gag-bcBdfdgdgdg-Z-Z-Z-Z-Z-B,iJ-ciY-cif-ciY-bpmix-ciM-chT-ciM-apm-acQ-gcU-gcJbXbl-cbl-ccJbXbl-cbl-cbY-cbi-bbfcJbXbl-cbl-ccJbXbl-cbl-ccg-gbu-giJ-aif-akN-aky-anb-cnb-bjUnb-bkNhTixiMjUnb-cnb-bjUnb-bkNifiJiYkg-Z-Z-Z-Z-Z-B,bP-cbP-cbP-caP-baUeS-ceS-ceS-cdS-adU-abP-cbP-cbP-ceP-cbRbraR-caR-cbRbraR-caR-cbs-cdN-cbRbraR-caR-cbRbraR-caR-cep-cdP-adC-adP-cdP-ceP-cbP-bhCaa-ccA-cca-cbn-caa-ccA-cca-cbxbxbxbx-Z-Z-Z-Z-Z-B,mZ-cmZ-cmZ-cmZ-biUmZ-cmZ-cmZ-cmZ-aiU-ake-gki-gmy-ckSkDlH-cmy-cjUjqlF-cjqjUkykNkNhTixiMmy-ckSkDlH-cmy-cjUjqlF-cjC-giY-ckK-akZ-acS-ccE-bcDaa-cdI-ccW-cbR-caa-cdI-ccW-ccgcgcgcg-Z-Z-Z-Z-Z-B\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"we-rise-from-your-demise\">\n  <h3><a class=\"anchor\" href=\"#we-rise-from-your-demise\" title=\"link to section\">#<\/a>Static Burst \u2014 We Rise From Your Demise (Concert Hall 5)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(We Rise From Your Demise)df-vdu-ccK-ccK-ccK-ccBcBcE-acK-acK-acK-acK-acK-acK-acBcBcA-aaX-caX-caX-caX-cba-cba-cba-ccz-caa-ccBcBcBcBaa-ccz-caa-ccBcBcBcBaa-ccz-caC-gaC-caC-acB-aba-cba-cba-caC-gaC-caJ-acB-adgdgdgdgbE-ccBcBcBcBbE-ccBcBcBcBbE-ccBcBcBcBaC-gaC-ccz-bcBba-cba-cba-cba-cba-cba-cba-ccz-cbj-cbj-cbj-cbj-cak-cak-cak-cak-acG-acB-acB-acB-acB-acB-acB-acB-acF-aaC-gaC-caC-acF-adg-Z-Z-B,dl-blo-bdl-bkZ-bbN-blo-bcz-hda-cda-aco-ada-cby-ack-ada-cda-aco-ada-cby-ack-aby-acW-ack-acW-aby-acW-ack-cby-acW-ack-acW-aby-acW-ack-cda-cbCefcoeRda-cbCefcoeRda-cbCefcoeRda-cbyebckeNbC-aco-ada-cbC-aco-ada-ack-aby-ack-acW-cby-aeb-acz-gco-cbC-aby-adldldldlck-ccW-cck-aeNebcW-cck-cby-ack-adl-ebNczdl-ebNczcW-ccW-cby-cck-cby-cck-ccW-ccW-apm-ada-cda-cda-cda-apm-acW-ccW-cby-cby-ack-acW-cby-cck-cby-abf-adl-gbN-ccz-cdl-Z-Z-B,ck-kbk-bcX-bbK-hck-gck-gck-gck-cba-abA-aba-aca-abA-aca-aba-aca-abA-cba-aca-abA-aca-aba-aca-abA-ccc-cbccPbCdpcc-cbccPbCdpcc-cbccPbCdpcc-cbacNbAdnbc-abC-acc-cbc-abC-acc-abA-aba-abA-aca-cba-acN-abK-gbK-cbk-aba-ackckckckbA-cca-cbA-adncNca-cbA-cba-abA-ack-ebkbKck-ebkbKca-cca-cba-cbA-cba-cbA-cca-cca-ccc-ccc-ccc-ccc-cca-cca-cba-cba-abA-aca-cba-cbA-cba-ahu-ack-gbk-cbK-cck-Z-Z-B,kv-bdl-biu-bcz-bjn-beq-bjR-hkv-alo-aiu-akZ-akv-alo-ajblcjF-akv-alo-aiu-akZ-akv-alo-ajblcjF-ajb-alc-ajF-akj-ajb-alc-ajF-ajbiMjb-alc-ajF-akj-ajb-alc-ajF-ajbiMkm-clciikNlckm-ciiiMjbiMkm-clciikNlckm-ciiiMjbiMiN-aijjciN-ciN-aijjciN-aiM-aiM-aiijbiM-ciM-ajbiMiu-giu-cjn-ajn-aiYiujniYii-ciMiijbiMjF-ajbiMiMiijbiMii-clciMiijbkv-elokZkv-elokZkj-ckj-alckNkj-ckj-alckNlc-cii-akN-akj-ciM-ckkldijkOkkldjciNkkldijkOkkldjciNkjlciikNkjlcjbiMjbiMiilcjbiMiilckjlciikNkjlcjbiMjbiMiilcjbiMlc-akZ-elolokZ-akv-clokZkv-Z-Z-B<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#we-rise-from-your-demise\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(We Rise From Your Demise)df-vdu-ccK-ccK-ccK-ccBcBcE-acK-acK-acK-acK-acK-acK-acBcBcA-aaX-caX-caX-caX-cba-cba-cba-ccz-caa-ccBcBcBcBaa-ccz-caa-ccBcBcBcBaa-ccz-caC-gaC-caC-acB-aba-cba-cba-caC-gaC-caJ-acB-adgdgdgdgbE-ccBcBcBcBbE-ccBcBcBcBbE-ccBcBcBcBaC-gaC-ccz-bcBba-cba-cba-cba-cba-cba-cba-ccz-cbj-cbj-cbj-cbj-cak-cak-cak-cak-acG-acB-acB-acB-acB-acB-acB-acB-acF-aaC-gaC-caC-acF-adg-Z-Z-B,dl-blo-bdl-bkZ-bbN-blo-bcz-hda-cda-aco-ada-cby-ack-ada-cda-aco-ada-cby-ack-aby-acW-ack-acW-aby-acW-ack-cby-acW-ack-acW-aby-acW-ack-cda-cbCefcoeRda-cbCefcoeRda-cbCefcoeRda-cbyebckeNbC-aco-ada-cbC-aco-ada-ack-aby-ack-acW-cby-aeb-acz-gco-cbC-aby-adldldldlck-ccW-cck-aeNebcW-cck-cby-ack-adl-ebNczdl-ebNczcW-ccW-cby-cck-cby-cck-ccW-ccW-apm-ada-cda-cda-cda-apm-acW-ccW-cby-cby-ack-acW-cby-cck-cby-abf-adl-gbN-ccz-cdl-Z-Z-B,ck-kbk-bcX-bbK-hck-gck-gck-gck-cba-abA-aba-aca-abA-aca-aba-aca-abA-cba-aca-abA-aca-aba-aca-abA-ccc-cbccPbCdpcc-cbccPbCdpcc-cbccPbCdpcc-cbacNbAdnbc-abC-acc-cbc-abC-acc-abA-aba-abA-aca-cba-acN-abK-gbK-cbk-aba-ackckckckbA-cca-cbA-adncNca-cbA-cba-abA-ack-ebkbKck-ebkbKca-cca-cba-cbA-cba-cbA-cca-cca-ccc-ccc-ccc-ccc-cca-cca-cba-cba-abA-aca-cba-cbA-cba-ahu-ack-gbk-cbK-cck-Z-Z-B,kv-bdl-biu-bcz-bjn-beq-bjR-hkv-alo-aiu-akZ-akv-alo-ajblcjF-akv-alo-aiu-akZ-akv-alo-ajblcjF-ajb-alc-ajF-akj-ajb-alc-ajF-ajbiMjb-alc-ajF-akj-ajb-alc-ajF-ajbiMkm-clciikNlckm-ciiiMjbiMkm-clciikNlckm-ciiiMjbiMiN-aijjciN-ciN-aijjciN-aiM-aiM-aiijbiM-ciM-ajbiMiu-giu-cjn-ajn-aiYiujniYii-ciMiijbiMjF-ajbiMiMiijbiMii-clciMiijbkv-elokZkv-elokZkj-ckj-alckNkj-ckj-alckNlc-cii-akN-akj-ciM-ckkldijkOkkldjciNkkldijkOkkldjciNkjlciikNkjlcjbiMjbiMiilcjbiMiilckjlciikNkjlcjbiMjbiMiilcjbiMlc-akZ-elolokZ-akv-clokZkv-Z-Z-B\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<h2 id=\"theater\">Theater<\/h2>\n<hgroup class=\"punkomatic-song\" id=\"no-threats-allowed\">\n  <h3><a class=\"anchor\" href=\"#no-threats-allowed\" title=\"link to section\">#<\/a>The Tribal Trooboos \u2014 No Threats Allowed (Theater 1)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(No Threats Allowed)-hbw-gbw-gbw-gbu-gbu-cdg-acRcDbt-gbt-ccX-acQcDbw-gbw-gbw-gbw-gbu-gbu-cdg-acRcDcC-acB-adg-cdu-cbY-edf-acY-ccY-caP-gcC-acB-abt-gbt-gbL-gbL-cdg-acRcDdg-Z-Z-Z-Z-U,gK-fcGgK-fcGgK-fcGgK-fcGcJ-ccJ-abX-acJ-ccO-acIbYgJ-fcKgJ-cdE-adlcSgK-fcGgK-fcGgK-fcGgK-fcGcJ-ccJ-abX-acJ-ccO-acIbYaPadbUcGgO-cgO-aaPadgO-cgO-abb-agO-cgM-cgO-cgM-caPadbUcGgJ-fcKgJ-fcKgJ-fcKgJ-cdE-adlcSbb-Z-Z-Z-Z-U,-hgl-fbOgl-fbOgl-fbObR-cbR-abr-abR-cbU-abQbsgk-fbSgk-ccx-ackbXgl-fbOgl-fbOgl-fbOgl-fbObR-cbR-abr-abR-cbU-abQbsaBabbobOgp-cgp-aaBabgp-cgp-aaK-agp-cgn-cgp-cgn-caBabbobOgk-fbSgk-fbSgk-fbSgk-ccx-ackbXaK-Z-Z-Z-Z-U,-pkz-ahUldkOkkkz-akD-ahYlhkSkokD-aiC-ciC-ahY-aiC-cnx-cmj-cmh-cmj-ckK-akvjCiJ-giL-gkz-ahUldkOkkkz-akD-ahYlhkSkokD-aiC-ciC-ahY-aiC-cnx-cnB-cbb-giy-ciy-aiJ-iiL-gnB-cmj-cmh-cmj-caPbUbicGmj-cmh-cmj-ckK-akvjCiJ-Z-Z-Z-Z-U<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#no-threats-allowed\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(No Threats Allowed)-hbw-gbw-gbw-gbu-gbu-cdg-acRcDbt-gbt-ccX-acQcDbw-gbw-gbw-gbw-gbu-gbu-cdg-acRcDcC-acB-adg-cdu-cbY-edf-acY-ccY-caP-gcC-acB-abt-gbt-gbL-gbL-cdg-acRcDdg-Z-Z-Z-Z-U,gK-fcGgK-fcGgK-fcGgK-fcGcJ-ccJ-abX-acJ-ccO-acIbYgJ-fcKgJ-cdE-adlcSgK-fcGgK-fcGgK-fcGgK-fcGcJ-ccJ-abX-acJ-ccO-acIbYaPadbUcGgO-cgO-aaPadgO-cgO-abb-agO-cgM-cgO-cgM-caPadbUcGgJ-fcKgJ-fcKgJ-fcKgJ-cdE-adlcSbb-Z-Z-Z-Z-U,-hgl-fbOgl-fbOgl-fbObR-cbR-abr-abR-cbU-abQbsgk-fbSgk-ccx-ackbXgl-fbOgl-fbOgl-fbOgl-fbObR-cbR-abr-abR-cbU-abQbsaBabbobOgp-cgp-aaBabgp-cgp-aaK-agp-cgn-cgp-cgn-caBabbobOgk-fbSgk-fbSgk-fbSgk-ccx-ackbXaK-Z-Z-Z-Z-U,-pkz-ahUldkOkkkz-akD-ahYlhkSkokD-aiC-ciC-ahY-aiC-cnx-cmj-cmh-cmj-ckK-akvjCiJ-giL-gkz-ahUldkOkkkz-akD-ahYlhkSkokD-aiC-ciC-ahY-aiC-cnx-cnB-cbb-giy-ciy-aiJ-iiL-gnB-cmj-cmh-cmj-caPbUbicGmj-cmh-cmj-ckK-akvjCiJ-Z-Z-Z-Z-U\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"the-crusaders\">\n  <h3><a class=\"anchor\" href=\"#the-crusaders\" title=\"link to section\">#<\/a>East of Here \u2014 The Crusaders (Theater 2)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(The Crusaders)cz-cbt-gbt-gbt-gbt-fcBbw-cbw-cbw-cbw-acC-abw-cbw-cbw-cbw-acD-abt-gbt-gbt-gbt-ecB-abt-cbx-cbx-cbx-ecB-abx-cbx-cbx-ecC-abw-cbw-cbw-fcDcK-ccL-bcCbt-gbt-gbt-gbt-gbv-gbv-ecD-aby-gby-ecB-aby-gby-ccC-acE-adf-Z-Z-Z-Q,ch-ccD-cbR-cbf-cbR-ccD-cbR-cbf-cbR-ccM-clY-aca-akN-aky-acM-aca-acM-clY-aca-akN-ahT-ahT-aix-acD-cbR-cbf-cbR-ccD-cbR-cbf-cbR-cmg-ciJ-aiJiJif-aifjCkZ-akZkZif-aifkKiJ-aiJiJif-aifjCkZ-akZkZkK-apm-amh-cmi-cmI-chY-akSkDkZ-gcD-cbR-cbf-cbR-ccD-cbR-cbf-cbR-ccE-cbS-cbg-cbS-ccD-cbR-cbf-cbR-ccD-cbR-cbf-cbR-ccS-Z-Z-Z-Q,by-cbN-cbn-caN-cbn-cbP-cbp-caP-cbp-cbS-cbn-caN-cbN-abn-abS-cbn-caN-cda-adC-abN-cbn-caN-cbn-cbN-cbn-caN-cbn-ceS-cbN-cbn-caN-cbn-cbN-cbn-caN-cbn-afk-abQ-cbQ-ccD-cbq-abs-acK-gbN-cbn-caN-cbn-cbP-cbp-caP-cbp-cbP-cbp-caP-cbp-cbN-cbn-caN-cbn-cbN-cbn-caN-cbn-cbX-Z-Z-Z-Q,ch-cmj-clS-clt-clu-cmj-clS-clt-clT-ccK-cbR-cbf-ccD-abR-acK-cbR-cbf-ceu-aaN-amj-clS-clt-clu-cmj-clS-clt-clT-cmq-amq-acF-cbT-cbh-cbT-ccF-cbT-cbh-cbT-afJ-acI-ccI-cdN-cbW-abY-adX-epm-amj-clS-clt-clu-cmj-clS-clt-clT-ccS-acScScg-acgcSbu-abucScg-acgbujU-cjq-ciM-chTkNky-ajU-cjq-ciM-chTkNkykNiJ-Z-Z-Z-Q<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#the-crusaders\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(The Crusaders)cz-cbt-gbt-gbt-gbt-fcBbw-cbw-cbw-cbw-acC-abw-cbw-cbw-cbw-acD-abt-gbt-gbt-gbt-ecB-abt-cbx-cbx-cbx-ecB-abx-cbx-cbx-ecC-abw-cbw-cbw-fcDcK-ccL-bcCbt-gbt-gbt-gbt-gbv-gbv-ecD-aby-gby-ecB-aby-gby-ccC-acE-adf-Z-Z-Z-Q,ch-ccD-cbR-cbf-cbR-ccD-cbR-cbf-cbR-ccM-clY-aca-akN-aky-acM-aca-acM-clY-aca-akN-ahT-ahT-aix-acD-cbR-cbf-cbR-ccD-cbR-cbf-cbR-cmg-ciJ-aiJiJif-aifjCkZ-akZkZif-aifkKiJ-aiJiJif-aifjCkZ-akZkZkK-apm-amh-cmi-cmI-chY-akSkDkZ-gcD-cbR-cbf-cbR-ccD-cbR-cbf-cbR-ccE-cbS-cbg-cbS-ccD-cbR-cbf-cbR-ccD-cbR-cbf-cbR-ccS-Z-Z-Z-Q,by-cbN-cbn-caN-cbn-cbP-cbp-caP-cbp-cbS-cbn-caN-cbN-abn-abS-cbn-caN-cda-adC-abN-cbn-caN-cbn-cbN-cbn-caN-cbn-ceS-cbN-cbn-caN-cbn-cbN-cbn-caN-cbn-afk-abQ-cbQ-ccD-cbq-abs-acK-gbN-cbn-caN-cbn-cbP-cbp-caP-cbp-cbP-cbp-caP-cbp-cbN-cbn-caN-cbn-cbN-cbn-caN-cbn-cbX-Z-Z-Z-Q,ch-cmj-clS-clt-clu-cmj-clS-clt-clT-ccK-cbR-cbf-ccD-abR-acK-cbR-cbf-ceu-aaN-amj-clS-clt-clu-cmj-clS-clt-clT-cmq-amq-acF-cbT-cbh-cbT-ccF-cbT-cbh-cbT-afJ-acI-ccI-cdN-cbW-abY-adX-epm-amj-clS-clt-clu-cmj-clS-clt-clT-ccS-acScScg-acgcSbu-abucScg-acgbujU-cjq-ciM-chTkNky-ajU-cjq-ciM-chTkNkykNiJ-Z-Z-Z-Q\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"as-flames-light-the-sky\">\n  <h3><a class=\"anchor\" href=\"#as-flames-light-the-sky\" title=\"link to section\">#<\/a>The Necromancers \u2014 As Flames Light The Sky (Theater 3)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(As Flames Light The Sky)-ddf-Icz-ccK-ccK-ccK-ccK-ccK-ccK-ccK-ccK-acH-acQ-ccQ-ccB-acB-acB-abvbybA-ecC-abA-ecC-abA-ecC-abA-ccC-acC-abE-ecC-abE-ecC-abE-ecC-abE-ccC-acC-aab-gbH-cbH-acC-aab-ecB-adfdfdfdfdfdfcC-acN-ccO-bcNdfdfdfdfdfdfdf-abE-gbE-gaa-caV-caa-aaaaacM-acB-abj-cbj-acB-abj-ccB-acB-aaX-caX-acC-aaX-caX-acC-aaX-caX-acC-aaX-ccC-acC-acB-acB-acB-acD-acB-acB-acB-acD-acB-acB-acB-acD-acB-acB-acD-acD-adf-c,bc-caZ-gjCjniJ-ejCjnif-ekZifiJ-ckZkZkK-cif-cjCjniJ-ejCjnif-ekZifiJ-ckZkZkK-cif-ciH-cbO-cbb-abb-abb-abb-ajqjbix-cix-ajqjbhT-chT-akNhTix-ckN-aky-cii-ajb-ajqjbix-cix-ajqjbhT-chT-akNhTix-ckN-aky-cii-ajb-akO-chU-cjqjbixhTixjbjqjUkO-chU-cjqjbixhTix-kbb!!bb!!cg!!cQ-aaMataMbybRbybRcDaMataMbybRbybRcDcD-abR-aaS-ccD-abR-aaS-apm-abb-gja-gjFjqiM-ciM-ajFjqii-cii-alciiiM-clc-akN-cix-ajq-ajFjqiM-ciM-ajFjqii-cii-alciiiM-clc-akN-cix-ajq-aiY-c,aL-caK-gaK-gaK-gak-gcK-cak-caK-gaK-gak-gcK-cak-caJ-kaK-aaK-aaA-caA-caa-caa-ccA-ccA-ccn-ccn-caA-caA-caa-caa-ccA-ccA-ccn-ccn-ccC-cac-caE-caE-ccC-cac-caE-caE-kaKaxaKbkbxbkbW-aaAanaAbabnbabnbNaAanaAbabnbabnbNbN-abn-aaE-cbN-abn-aaE-kaZ-gaN-caN-can-can-ccN-ccN-ccA-ccA-caN-caN-can-can-ccN-ccN-ccA-ccA-caX-c,kL-ciy-ciy-ciy-ciy-ciy-ciy-chU-chU-ckO-chU-caN-caN-caN-caN-cab-cab-cdJ-cab-caS-caS-caS-caS-apm-aaM-caM-caa-caa-cdI-cdI-cdp-cdp-caM-caM-caa-caa-cdI-cdI-cdp-cdp-cdM-cae-caS-caS-cdM-cae-caS-caS-caNauaNbzbSbzbScE!!aI!!bN!!bNcQ-aaMataMbybRbybRcDaMataMbybRbybRcDcD-abR-aaS-ccD-abR-aaS-apn-a!!-gbw-gbf-cbf-cat-cat-ceb-ceb-cdI-cdI-cbf-cbf-cat-cat-ceb-ceb-cdI-cdI-cbu-c<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#as-flames-light-the-sky\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(As Flames Light The Sky)-ddf-Icz-ccK-ccK-ccK-ccK-ccK-ccK-ccK-ccK-acH-acQ-ccQ-ccB-acB-acB-abvbybA-ecC-abA-ecC-abA-ecC-abA-ccC-acC-abE-ecC-abE-ecC-abE-ecC-abE-ccC-acC-aab-gbH-cbH-acC-aab-ecB-adfdfdfdfdfdfcC-acN-ccO-bcNdfdfdfdfdfdfdf-abE-gbE-gaa-caV-caa-aaaaacM-acB-abj-cbj-acB-abj-ccB-acB-aaX-caX-acC-aaX-caX-acC-aaX-caX-acC-aaX-ccC-acC-acB-acB-acB-acD-acB-acB-acB-acD-acB-acB-acB-acD-acB-acB-acD-acD-adf-c,bc-caZ-gjCjniJ-ejCjnif-ekZifiJ-ckZkZkK-cif-cjCjniJ-ejCjnif-ekZifiJ-ckZkZkK-cif-ciH-cbO-cbb-abb-abb-abb-ajqjbix-cix-ajqjbhT-chT-akNhTix-ckN-aky-cii-ajb-ajqjbix-cix-ajqjbhT-chT-akNhTix-ckN-aky-cii-ajb-akO-chU-cjqjbixhTixjbjqjUkO-chU-cjqjbixhTix-kbb!!bb!!cg!!cQ-aaMataMbybRbybRcDaMataMbybRbybRcDcD-abR-aaS-ccD-abR-aaS-apm-abb-gja-gjFjqiM-ciM-ajFjqii-cii-alciiiM-clc-akN-cix-ajq-ajFjqiM-ciM-ajFjqii-cii-alciiiM-clc-akN-cix-ajq-aiY-c,aL-caK-gaK-gaK-gak-gcK-cak-caK-gaK-gak-gcK-cak-caJ-kaK-aaK-aaA-caA-caa-caa-ccA-ccA-ccn-ccn-caA-caA-caa-caa-ccA-ccA-ccn-ccn-ccC-cac-caE-caE-ccC-cac-caE-caE-kaKaxaKbkbxbkbW-aaAanaAbabnbabnbNaAanaAbabnbabnbNbN-abn-aaE-cbN-abn-aaE-kaZ-gaN-caN-can-can-ccN-ccN-ccA-ccA-caN-caN-can-can-ccN-ccN-ccA-ccA-caX-c,kL-ciy-ciy-ciy-ciy-ciy-ciy-chU-chU-ckO-chU-caN-caN-caN-caN-cab-cab-cdJ-cab-caS-caS-caS-caS-apm-aaM-caM-caa-caa-cdI-cdI-cdp-cdp-caM-caM-caa-caa-cdI-cdI-cdp-cdp-cdM-cae-caS-caS-cdM-cae-caS-caS-caNauaNbzbSbzbScE!!aI!!bN!!bNcQ-aaMataMbybRbybRcDaMataMbybRbybRcDcD-abR-aaS-ccD-abR-aaS-apn-a!!-gbw-gbf-cbf-cat-cat-ceb-ceb-cdI-cdI-cbf-cbf-cat-cat-ceb-ceb-cdI-cdI-cbu-c\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"a-doped-up-dream\">\n  <h3><a class=\"anchor\" href=\"#a-doped-up-dream\" title=\"link to section\">#<\/a>The Dudes \u2014 A Doped Up Dream (Theater 4)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(A Doped Up Dream)-hcL-ccz-caD-caD-aaU-aaD-caI-caD-caD-aba-aaD-caD-acC-abZ-ecJ-acy-gcy-ccz-ccC-aaa-eba-aab-ecB-aaf-eba-aaD-gaD-gca-gca-ccz-bdh-Z-Z-Z-Z-Z-X,-hdI-cdI-cdI-aeu-acGcGcH-adI-aeu-acH-cdI-aeu-acGcGcH-adI-aeu-acH-cdX-ocT-caN-abgbfcQ-adI-aeu-acD-acH-adI-aeu-acH-cdI-aeu-acD-acH-adI-aeu-acDcE-bdI-aeu-acDcE-bdX-aeJ-acScE-bdX-aeJ-acE-bcQ-Z-Z-Z-Z-Z-X,-hcA-ccA-ccA-ada-abObObP-acA-ada-abP-ccA-ada-abObObP-acA-ada-abP-ccC-ccC-cbP-cdC-adP-aeP-cdC-adP-abW-acA-ada-abN-abP-acA-ada-abP-ccA-ada-abN-abP-acA-ada-abNbN-bcA-ada-abNbN-bcK-adk-abXbN-bcK-adk-abN-bbW-Z-Z-Z-Z-Z-X,mn-cmn-cmn-cmn-cmI-cmw-cmK-cmy-cmM-cml-cmG-cmw-ckZ-gmv-cmA-cmv-cmA-cke-amI-cmw-cmK-cmy-cmM-cml-cmG-cmG-cmG-cmG-cmG-ckgjV-bmG-cjV-bke-Z-Z-Z-Z-Z-X<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#a-doped-up-dream\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(A Doped Up Dream)-hcL-ccz-caD-caD-aaU-aaD-caI-caD-caD-aba-aaD-caD-acC-abZ-ecJ-acy-gcy-ccz-ccC-aaa-eba-aab-ecB-aaf-eba-aaD-gaD-gca-gca-ccz-bdh-Z-Z-Z-Z-Z-X,-hdI-cdI-cdI-aeu-acGcGcH-adI-aeu-acH-cdI-aeu-acGcGcH-adI-aeu-acH-cdX-ocT-caN-abgbfcQ-adI-aeu-acD-acH-adI-aeu-acH-cdI-aeu-acD-acH-adI-aeu-acDcE-bdI-aeu-acDcE-bdX-aeJ-acScE-bdX-aeJ-acE-bcQ-Z-Z-Z-Z-Z-X,-hcA-ccA-ccA-ada-abObObP-acA-ada-abP-ccA-ada-abObObP-acA-ada-abP-ccC-ccC-cbP-cdC-adP-aeP-cdC-adP-abW-acA-ada-abN-abP-acA-ada-abP-ccA-ada-abN-abP-acA-ada-abNbN-bcA-ada-abNbN-bcK-adk-abXbN-bcK-adk-abN-bbW-Z-Z-Z-Z-Z-X,mn-cmn-cmn-cmn-cmI-cmw-cmK-cmy-cmM-cml-cmG-cmw-ckZ-gmv-cmA-cmv-cmA-cke-amI-cmw-cmK-cmy-cmM-cml-cmG-cmG-cmG-cmG-cmG-ckgjV-bmG-cjV-bke-Z-Z-Z-Z-Z-X\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"death-insurance\">\n  <h3><a class=\"anchor\" href=\"#death-insurance\" title=\"link to section\">#<\/a>Bloody Herring \u2014 Death Insurance (Theater 5)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Death Insurance)-fcO-abw-gdf-gbw-gbw-gbw-gbw-gbw-gbG-gbG-gbw-gbw-gbw-gbw-gbw-gbw-gbG-gbG-gai-cai-cai-cai-cai-cai-cdfcO-bbH-gbH-fcCbw-gbw-gdf-cdf-acB-abw-gbw-gbG-gbG-ecB-abw-gbw-gdf-Z-Z-Z-w,gM-cgM-abf-agM-cgM-abf-agO-cgO-aab-agO-cgO-aaabfgO-cgO-aadbigO-cgO-aaabfbW-cbW-cbW-cbW-cgt-cgt-cgt-cgt-cgO-cgO-aab-agO-cgO-aaabfgO-cgO-aadbigO-cgO-aaabfbW-cbW-cbW-cbW-cgt-cgt-cgt-cgt-ahM-ahM-ghM-ghM-ghu-chu-chu-chu-chu-bhFhK-chK-chK-chK-cbu-cbN-acp-abW-cbW-cbW-cbW-cgt-cgt-cgt-cgt-aax-agM-cgM-abf-agM-cgM-abf-aaZ-Z-Z-Z-w,gn-cgn-aaN-agn-cgn-aaN-agp-cgp-aaa-agp-cgp-aaaaNgp-cgp-aabaOgp-cgp-aaaaNbq-cbq-cbq-cbq-cfU-cfU-cfU-cfU-cgp-cgp-aaa-agp-cgp-aaaaNgp-cgp-aabaOgp-cgp-aaaaNbq-cbq-cbq-cbq-cfU-cfU-cfU-cfU-ahn-ahn-ghn-ghn-kgV-cgV-cgV-cgV-bhghl-chl-chl-chl-caX-cbk-abD-abq-cbq-cbq-cbq-cfU-cfU-cfU-cfU-aap-agn-cgn-aaN-agn-cgn-aaN-aaJ-Z-Z-Z-w,nv-cnv-abf-anv-cnv-aix-agO-cgO-aab-agO-cgO-ahTiMgO-cgO-ahViOgO-cgO-ahTiMjx-cjM-aiTjMjx-cjM-aiTjMjy-ciU-cjy-ciU-ajN-aiA-aiU-aiA-ahT-aiA-aiU-aiA-ahTiMnC-anF-anC-cnC-anF-anC-ahTiMjx-cjM-aiTjMjx-cjM-aiTjMjy-ciU-cjy-ciU-ajNjypj-apc-aoX-cpj-apc-aoX-biipj-apc-aoX-ghu-chu-chu-chu-bhFoQ-boSoQ-aoS-aoQ-boSoQ-aoS-aiY-cjn-ajM-ajx-cjM-aiTjMjx-cjM-aiTjMjy-ciU-cjy-ciU-ajI-anw-cnC-aiM-anw-cnE-aiM-aiH-Z-Z-Z-w<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#death-insurance\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Death Insurance)-fcO-abw-gdf-gbw-gbw-gbw-gbw-gbw-gbG-gbG-gbw-gbw-gbw-gbw-gbw-gbw-gbG-gbG-gai-cai-cai-cai-cai-cai-cdfcO-bbH-gbH-fcCbw-gbw-gdf-cdf-acB-abw-gbw-gbG-gbG-ecB-abw-gbw-gdf-Z-Z-Z-w,gM-cgM-abf-agM-cgM-abf-agO-cgO-aab-agO-cgO-aaabfgO-cgO-aadbigO-cgO-aaabfbW-cbW-cbW-cbW-cgt-cgt-cgt-cgt-cgO-cgO-aab-agO-cgO-aaabfgO-cgO-aadbigO-cgO-aaabfbW-cbW-cbW-cbW-cgt-cgt-cgt-cgt-ahM-ahM-ghM-ghM-ghu-chu-chu-chu-chu-bhFhK-chK-chK-chK-cbu-cbN-acp-abW-cbW-cbW-cbW-cgt-cgt-cgt-cgt-aax-agM-cgM-abf-agM-cgM-abf-aaZ-Z-Z-Z-w,gn-cgn-aaN-agn-cgn-aaN-agp-cgp-aaa-agp-cgp-aaaaNgp-cgp-aabaOgp-cgp-aaaaNbq-cbq-cbq-cbq-cfU-cfU-cfU-cfU-cgp-cgp-aaa-agp-cgp-aaaaNgp-cgp-aabaOgp-cgp-aaaaNbq-cbq-cbq-cbq-cfU-cfU-cfU-cfU-ahn-ahn-ghn-ghn-kgV-cgV-cgV-cgV-bhghl-chl-chl-chl-caX-cbk-abD-abq-cbq-cbq-cbq-cfU-cfU-cfU-cfU-aap-agn-cgn-aaN-agn-cgn-aaN-aaJ-Z-Z-Z-w,nv-cnv-abf-anv-cnv-aix-agO-cgO-aab-agO-cgO-ahTiMgO-cgO-ahViOgO-cgO-ahTiMjx-cjM-aiTjMjx-cjM-aiTjMjy-ciU-cjy-ciU-ajN-aiA-aiU-aiA-ahT-aiA-aiU-aiA-ahTiMnC-anF-anC-cnC-anF-anC-ahTiMjx-cjM-aiTjMjx-cjM-aiTjMjy-ciU-cjy-ciU-ajNjypj-apc-aoX-cpj-apc-aoX-biipj-apc-aoX-ghu-chu-chu-chu-bhFoQ-boSoQ-aoS-aoQ-boSoQ-aoS-aiY-cjn-ajM-ajx-cjM-aiTjMjx-cjM-aiTjMjy-ciU-cjy-ciU-ajI-anw-cnC-aiM-anw-cnE-aiM-aiH-Z-Z-Z-w\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<h2 id=\"stadium\">Stadium<\/h2>\n<hgroup class=\"punkomatic-song\" id=\"empty-octopus-glasses\">\n  <h3><a class=\"anchor\" href=\"#empty-octopus-glasses\" title=\"link to section\">#<\/a>Jurassic Octopus \u2014 Empty Octopus Glasses (Stadium 1)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Empty Octopus Glasses)df-acB-adf-acBcBbc-acB-abc-acE-abp-gbp-gbs-abs-abs-abs-abp-abp-abpbpcD-acB-acB-acB-acBcBcB-acB-acB-acBcBaD-gaD-gaF-gaF-ecB-aaa-gaa-gaf-gaf-gcD-acK-ccK-ccK-ccK-adg-abz-gbD-gbC-gbC-cbCbCcC-adf-bcBdf-bcBbI-gcB-acB-acB-acB-acB-acB-acB-acBcBdf-bdg-Z-Z-Z-Z-r,bQ-acg-abQ-acgcSbN-acg-abN-acgcSbJ-acc-abJ-acOccbJ-acc-abJ-acOccbJ-acc-abJ-acOccbJ-acc-abJ-acOccbJ-acc-abJ-acOccbJ-acc-abJ-acOccbN-qlo-a!!kK!!-ajn-a!!-aif!!kg!!bG-aej-aeCdxej-abG-aej-aeCdxcLcsbQ-aet-aeMdHet-abQ-aet-aeMdHcVcCpm!!-hbN-bcgbN-abs-abQ-bcjbQ-bbxbQ-bcjbQ-bbxby-aeb-aeudpeb-aby-aeb-aeudpcDckbQ-bcgbQ-bbubQ-bcjbQ-bbxbQ-bcjbQ-bbxby-bbRby-bbfbQ-bbL-Z-Z-Z-Z-r,-pbh-abu-abh-abUbubh-abu-abh-abUbubh-abu-abh-abUbubh-abu-abh-abUbubh-abu-abh-abUbubh-abu-abh-abUbuek-acX-adkcxcX-aek-acX-adkcxbXbKek-acX-adkcxcX-aek-acX-adkcxbXbKbg-acT-adgctcT-abg-acT-adgctbTbGbg-acT-adgctcT-abg-acT-adgctbTbG!!-ibk-bbxbk-aaW-abg-bbtbg-baTbg-bbtbg-baTba-acN-adacncN-aba-acN-adacnbNbAbj-bbxbj-baXbk-bbxbk-baXba-bbnba-baNba-bbnba-baN!!-bbj-Z-Z-Z-Z-r,-bcg-a!!-acgcSbQ-acj-abQ-acjcV!!-gji-cji-clj-clj-clj-clj-cbQ-acj-abQ-acVcjbQ-acj-abQ-acVcj!!-ojn-a!!-aif!!lo-a!!-alo-a!!kK!!jRbG-aej-aeCdxej-abG-aej-aeCdxcLcsbG-aej-aeCdxej-abG-aej-aeCdxcLcs!!pnbG-bbZbG-bbnbG-bbZbG-abs-abG-bbZbG-bbnbG-bbZbG-bbnby-aeb-aeudpeb-aby-aeb-aeudpcDckbL-bcgbL-bbubN-bcgbN-bbuby-bbRby-bbfby-bbRby-bbf!!-bbL-Z-Z-Z-Z-r<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#empty-octopus-glasses\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Empty Octopus Glasses)df-acB-adf-acBcBbc-acB-abc-acE-abp-gbp-gbs-abs-abs-abs-abp-abp-abpbpcD-acB-acB-acB-acBcBcB-acB-acB-acBcBaD-gaD-gaF-gaF-ecB-aaa-gaa-gaf-gaf-gcD-acK-ccK-ccK-ccK-adg-abz-gbD-gbC-gbC-cbCbCcC-adf-bcBdf-bcBbI-gcB-acB-acB-acB-acB-acB-acB-acBcBdf-bdg-Z-Z-Z-Z-r,bQ-acg-abQ-acgcSbN-acg-abN-acgcSbJ-acc-abJ-acOccbJ-acc-abJ-acOccbJ-acc-abJ-acOccbJ-acc-abJ-acOccbJ-acc-abJ-acOccbJ-acc-abJ-acOccbN-qlo-a!!kK!!-ajn-a!!-aif!!kg!!bG-aej-aeCdxej-abG-aej-aeCdxcLcsbQ-aet-aeMdHet-abQ-aet-aeMdHcVcCpm!!-hbN-bcgbN-abs-abQ-bcjbQ-bbxbQ-bcjbQ-bbxby-aeb-aeudpeb-aby-aeb-aeudpcDckbQ-bcgbQ-bbubQ-bcjbQ-bbxbQ-bcjbQ-bbxby-bbRby-bbfbQ-bbL-Z-Z-Z-Z-r,-pbh-abu-abh-abUbubh-abu-abh-abUbubh-abu-abh-abUbubh-abu-abh-abUbubh-abu-abh-abUbubh-abu-abh-abUbuek-acX-adkcxcX-aek-acX-adkcxbXbKek-acX-adkcxcX-aek-acX-adkcxbXbKbg-acT-adgctcT-abg-acT-adgctbTbGbg-acT-adgctcT-abg-acT-adgctbTbG!!-ibk-bbxbk-aaW-abg-bbtbg-baTbg-bbtbg-baTba-acN-adacncN-aba-acN-adacnbNbAbj-bbxbj-baXbk-bbxbk-baXba-bbnba-baNba-bbnba-baN!!-bbj-Z-Z-Z-Z-r,-bcg-a!!-acgcSbQ-acj-abQ-acjcV!!-gji-cji-clj-clj-clj-clj-cbQ-acj-abQ-acVcjbQ-acj-abQ-acVcj!!-ojn-a!!-aif!!lo-a!!-alo-a!!kK!!jRbG-aej-aeCdxej-abG-aej-aeCdxcLcsbG-aej-aeCdxej-abG-aej-aeCdxcLcs!!pnbG-bbZbG-bbnbG-bbZbG-abs-abG-bbZbG-bbnbG-bbZbG-bbnby-aeb-aeudpeb-aby-aeb-aeudpcDckbL-bcgbL-bbubN-bcgbN-bbuby-bbRby-bbfby-bbRby-bbf!!-bbL-Z-Z-Z-Z-r\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"vulturis\">\n  <h3><a class=\"anchor\" href=\"#vulturis\" title=\"link to section\">#<\/a>Calibur 12 \u2014 Vulturis (Stadium 2)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Vulturis)du-wcw-gcw-gcw-ccw-ccw-ccy-cbI-cbP-cbI-cbP-cbL-cbS-cbL-bcDcz-cdhcDag-cag-bcBab-cag-cag-acC-aag-cag-cag-gag-ecC-aae-cae-acC-aaf-ecC-aaU-cba-caU-cba-caU-caX-acD-adf-cdu-Z-Z-Z-Z-Z-a,jS-oiJ-siJ-gjR-cjI-cjI-cjF-cjq-cix-cii-cjF-cjq-cix-cjG-ajF-ajP-ajFjbkylcii-cixiilckyiilckykjlh-bjbjF-ajb-aix-aii-aky-cii-ajb-aix-aii-aky-alciikz-ckz-cix-aii-aky-alciikB-cil-aje-aiA-cil-akB-aiA-cii-akylcil-alf-akB-c!!-Z-Z-Z-Z-W,eL-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceA-ceA-ceA-ceA-ceA-ceA-ceA-ceA-ceJ-abA-cbA-ccN-ccn-cbe-caA-caA-ccn-ccn-ccN-ccN-ccn-ccn-ccN-ccN-ccp-ccp-ccP-ccP-cdC-cdC-ccx-g!!-Z-Z-Z-Z-W,jS-kjC-gjR-cjR-gjC-gkg-ccz-cco-cco-cck-cck-cck-cck-cck-cck-cck-ccl-ack-acx-ajFjbkylciukvkKloeb-cdp-cjg-cix-cfg-cdp-cdp-ceb-ceb-cdq-cdq-cec-cec-cdt-cdt-cef-cef-cfk-cfk-cdE-g!!-Z-Z-Z-Z-W<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#vulturis\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Vulturis)du-wcw-gcw-gcw-ccw-ccw-ccy-cbI-cbP-cbI-cbP-cbL-cbS-cbL-bcDcz-cdhcDag-cag-bcBab-cag-cag-acC-aag-cag-cag-gag-ecC-aae-cae-acC-aaf-ecC-aaU-cba-caU-cba-caU-caX-acD-adf-cdu-Z-Z-Z-Z-Z-a,jS-oiJ-siJ-gjR-cjI-cjI-cjF-cjq-cix-cii-cjF-cjq-cix-cjG-ajF-ajP-ajFjbkylcii-cixiilckyiilckykjlh-bjbjF-ajb-aix-aii-aky-cii-ajb-aix-aii-aky-alciikz-ckz-cix-aii-aky-alciikB-cil-aje-aiA-cil-akB-aiA-cii-akylcil-alf-akB-c!!-Z-Z-Z-Z-W,eL-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceC-ceA-ceA-ceA-ceA-ceA-ceA-ceA-ceA-ceJ-abA-cbA-ccN-ccn-cbe-caA-caA-ccn-ccn-ccN-ccN-ccn-ccn-ccN-ccN-ccp-ccp-ccP-ccP-cdC-cdC-ccx-g!!-Z-Z-Z-Z-W,jS-kjC-gjR-cjR-gjC-gkg-ccz-cco-cco-cck-cck-cck-cck-cck-cck-cck-ccl-ack-acx-ajFjbkylciukvkKloeb-cdp-cjg-cix-cfg-cdp-cdp-ceb-ceb-cdq-cdq-cec-cec-cdt-cdt-cef-cef-cfk-cfk-cdE-g!!-Z-Z-Z-Z-W\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"going-nowhere\">\n  <h3><a class=\"anchor\" href=\"#going-nowhere\" title=\"link to section\">#<\/a>Fenix Revolution \u2014 Going Nowhere (Stadium 3)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Going Nowhere)-paY-caY-cbL-cba-cdg-cdu-cak-cak-cak-cak-cak-cak-caX-acC-aag-gag-gag-gag-ecC-aaO-gaO-gaO-caP-caO-bcBaP-bcDaH-gaH-ccz-bcDdg-cdu-cdi-Z-Z-Z-Z-Z-w,bu-ccz-ceq-cdl-cbp-ccu-ceb-ccW-cbu-gbw-giM-aii-aiM-ajqjFiM-aii-aiM-ajqjFpd-cbf-cat-ceb-ccW-cbf-cat-ceb-ccW-apm-abj-cef-cco-cdM-cbj-cef-cco-cdM-ccX-ccX-bdJed-ceP-cbh-cbh-cbs-Z-Z-Z-Z-Z-w,aX-cbK-ccX-cck-acbbBaT-cbG-ccN-cca-acbbBaX-gaZ-gaN-abA-acN-aca-aaN-abA-acN-aca-acS-acfbFdS-cds-ccS-ccf-cdS-cds-ccS-ccf-caX-gbK-gaX-ccX-cbK-ccK-cca-cca-bcAcN-cdn-caX-Z-Z-Z-Z-Z-E,oj-coi-col-ciR-aiM-aoj-coi-col-ciR-aiM-aiN-ciN-ciS-bioiS-biooj-aoi-aol-aiM-apj-cor-cpj-ciM-biikN-bkjkN-biikN-bkjoo-cop-cjFjqiMkNkj-ajJ-aiY-giu-goj-ciY-coE-ciY-aiu-alo-ckZ-alojRiY-cjR-ajC-aiY-giW-Z-Z-Z-Z-Z-w<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#going-nowhere\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Going Nowhere)-paY-caY-cbL-cba-cdg-cdu-cak-cak-cak-cak-cak-cak-caX-acC-aag-gag-gag-gag-ecC-aaO-gaO-gaO-caP-caO-bcBaP-bcDaH-gaH-ccz-bcDdg-cdu-cdi-Z-Z-Z-Z-Z-w,bu-ccz-ceq-cdl-cbp-ccu-ceb-ccW-cbu-gbw-giM-aii-aiM-ajqjFiM-aii-aiM-ajqjFpd-cbf-cat-ceb-ccW-cbf-cat-ceb-ccW-apm-abj-cef-cco-cdM-cbj-cef-cco-cdM-ccX-ccX-bdJed-ceP-cbh-cbh-cbs-Z-Z-Z-Z-Z-w,aX-cbK-ccX-cck-acbbBaT-cbG-ccN-cca-acbbBaX-gaZ-gaN-abA-acN-aca-aaN-abA-acN-aca-acS-acfbFdS-cds-ccS-ccf-cdS-cds-ccS-ccf-caX-gbK-gaX-ccX-cbK-ccK-cca-cca-bcAcN-cdn-caX-Z-Z-Z-Z-Z-E,oj-coi-col-ciR-aiM-aoj-coi-col-ciR-aiM-aiN-ciN-ciS-bioiS-biooj-aoi-aol-aiM-apj-cor-cpj-ciM-biikN-bkjkN-biikN-bkjoo-cop-cjFjqiMkNkj-ajJ-aiY-giu-goj-ciY-coE-ciY-aiu-alo-ckZ-alojRiY-cjR-ajC-aiY-giW-Z-Z-Z-Z-Z-w\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"a-post-war-generation\">\n  <h3><a class=\"anchor\" href=\"#a-post-war-generation\" title=\"link to section\">#<\/a>The White Divinities \u2014 A Post-War Generation (Stadium 4)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(A Post-War Generation)cW-acVcR-ccw-ccC-acB-acD-acC-adf-ccR-adf-abw-gbw-gbw-gbw-cby-acC-abt-bbtbt-bcBbt-bbtbt-bcBbt-fcBbt-fcB-acBcD-abt-gbt-gbt-ecB-abw-cbw-abw-abw-cbw-abwcBbt-cbt-abtbtbt-cbt-abtcBdf-acW-ccW-acP-ccP-ccP-ccP-ccO-ccO-ccS-ccF-acC-adf-bdfdf-bcFcw-bcwcw-bcBcD-acC-abt-bbtbt-bcBbt-bbtbt-bcBbt-fcBbt-fcBdf-bdfdf-adu-adf-Z-Z-Z-F,-cgo-cgo-cgo-cgo-apm-agp-cgp-aap-agq-cgG-cgq-cgG-cgH-cgG-cgH-cgr-caa-bbfbR-bbfaa-bbfbR-bbfaa-bbfbR-bbfaa-bbfbR-bbfgBaIgBapar-caJ-car-cbv-aaJ-aar-gag-cbX-ablaSag-cbX-ablcJag-cbX-ablaSag-cbX-ablcJap-ggF-cgB-cgF-cgB-cgF-cgB-cgF-cgB-caa-bbfbR-bbfaa-bbfbR-bbfaabRcD!!aa-bbfbR-bbfaa-bbfbR-bbfaa-bbfbR-bbfaa-bbfbR-bbfap-bbucg-bbuap-Z-Z-Z-F,-ofP-ahx-ifR-cgh-cfR-cgh-cgi-cgh-cgi-cfS-caa-baNbn-baNaa-baNbn-baNaa-baNbn-baNaa-baNbn-baNgcaxgcakam-cay-cam-caY-aay-aam-gae-cbr-aaRaEae-cbr-aaRbRae-cbr-aaRaEae-cbr-aaRbRak-ggg-cgc-cgg-cgc-cgg-cgc-cgg-cgc-caa-baNbn-baNaa-baNbn-baNaabnbN!!aa-baNbn-baNaa-baNbn-baNaa-baNbn-baNaa-baNbn-baNak-baXbx-baXak-Z-Z-Z-F,-ghZ-ahZ-ahZ-ahZ-apn-knb-cnd-cnc-cnt-ano-anp-cna-cnn-cna-cnc-cnc-and-anc-cnc-and-amZ-cmZ-bnfmZ-cmZ-bnf-dap-gar-cbv-aaJ-aar-gno-cno-anq-ant-anp-ann-cnj-gnj-cnk-cna-cna-aap-ana-cmf-ami-ana-cnm-cna-cmf-ami-ana-cne-cmZ-cmZ-bnfmZ-cmZ-bnf!!-cnc-cnc-and-anc-cnc-and-amZ-cmZ-bnfmZ-cmZ-bnfmZ-cmZ-bnfap-Z-Z-Z-F<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#a-post-war-generation\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(A Post-War Generation)cW-acVcR-ccw-ccC-acB-acD-acC-adf-ccR-adf-abw-gbw-gbw-gbw-cby-acC-abt-bbtbt-bcBbt-bbtbt-bcBbt-fcBbt-fcB-acBcD-abt-gbt-gbt-ecB-abw-cbw-abw-abw-cbw-abwcBbt-cbt-abtbtbt-cbt-abtcBdf-acW-ccW-acP-ccP-ccP-ccP-ccO-ccO-ccS-ccF-acC-adf-bdfdf-bcFcw-bcwcw-bcBcD-acC-abt-bbtbt-bcBbt-bbtbt-bcBbt-fcBbt-fcBdf-bdfdf-adu-adf-Z-Z-Z-F,-cgo-cgo-cgo-cgo-apm-agp-cgp-aap-agq-cgG-cgq-cgG-cgH-cgG-cgH-cgr-caa-bbfbR-bbfaa-bbfbR-bbfaa-bbfbR-bbfaa-bbfbR-bbfgBaIgBapar-caJ-car-cbv-aaJ-aar-gag-cbX-ablaSag-cbX-ablcJag-cbX-ablaSag-cbX-ablcJap-ggF-cgB-cgF-cgB-cgF-cgB-cgF-cgB-caa-bbfbR-bbfaa-bbfbR-bbfaabRcD!!aa-bbfbR-bbfaa-bbfbR-bbfaa-bbfbR-bbfaa-bbfbR-bbfap-bbucg-bbuap-Z-Z-Z-F,-ofP-ahx-ifR-cgh-cfR-cgh-cgi-cgh-cgi-cfS-caa-baNbn-baNaa-baNbn-baNaa-baNbn-baNaa-baNbn-baNgcaxgcakam-cay-cam-caY-aay-aam-gae-cbr-aaRaEae-cbr-aaRbRae-cbr-aaRaEae-cbr-aaRbRak-ggg-cgc-cgg-cgc-cgg-cgc-cgg-cgc-caa-baNbn-baNaa-baNbn-baNaabnbN!!aa-baNbn-baNaa-baNbn-baNaa-baNbn-baNaa-baNbn-baNak-baXbx-baXak-Z-Z-Z-F,-ghZ-ahZ-ahZ-ahZ-apn-knb-cnd-cnc-cnt-ano-anp-cna-cnn-cna-cnc-cnc-and-anc-cnc-and-amZ-cmZ-bnfmZ-cmZ-bnf-dap-gar-cbv-aaJ-aar-gno-cno-anq-ant-anp-ann-cnj-gnj-cnk-cna-cna-aap-ana-cmf-ami-ana-cnm-cna-cmf-ami-ana-cne-cmZ-cmZ-bnfmZ-cmZ-bnf!!-cnc-cnc-and-anc-cnc-and-amZ-cmZ-bnfmZ-cmZ-bnfmZ-cmZ-bnfap-Z-Z-Z-F\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"not-so-lethal-buns\">\n  <h3><a class=\"anchor\" href=\"#not-so-lethal-buns\" title=\"link to section\">#<\/a>Solanum Slaves \u2014 Not So Lethal Buns (Stadium 5)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Not So Lethal Buns)-hcg-gcg-gcg-gcj-gcj-gcm-gcm-gcg-gcg-gch-gch-gcq-gcq-gdf-cdu-cch-gch-gch-gdf-Z-Z-Z-Z-Z-I,fV-afV-afV-afR-afV-afV-afV-afR-afV-afV-afV-afR-afV-afV-afV-afR-afA-gfA-gfR-afA-efR-afA-efR-afA-efR-afA-efV-afV-afV-afR-afV-afV-afV-afR-afA-gfA-gfW-afW-afW-cfW-afW-afW-cfW-afW-afW-cfW-afW-afW-cfW-afW-afW-ccS-Z-Z-Z-Z-Z-A,fw-afw-afw-afs-afw-afw-afw-afs-afw-afw-afw-afs-afw-afw-afw-afs-afb-gfb-gfs-afb-efs-afb-efs-afb-efs-afb-efw-afw-afw-afs-afw-afw-afw-afs-afb-gfb-gfx-afx-afx-cfx-afx-afx-cfx-afx-afx-cfx-afx-afx-cfx-afx-afx-cbX-Z-Z-Z-Z-Z-A,-pmr-aml-amr-amo-amr-aml-amr-amo-amq-ami-amq-amw-amq-ami-amq-amw-apu-gpu-gmw-amp-emw-amp-emr-aml-amr-amo-amr-aml-amr-amo-amq-ami-amq-amw-amq-ami-amq-amw-apu-omx-amx-amq-amw-amx-amx-amq-amB-amx-amx-amq-amw-amx-amx-amq-apu-Z-Z-Z-Z-Z-u<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#not-so-lethal-buns\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Not So Lethal Buns)-hcg-gcg-gcg-gcj-gcj-gcm-gcm-gcg-gcg-gch-gch-gcq-gcq-gdf-cdu-cch-gch-gch-gdf-Z-Z-Z-Z-Z-I,fV-afV-afV-afR-afV-afV-afV-afR-afV-afV-afV-afR-afV-afV-afV-afR-afA-gfA-gfR-afA-efR-afA-efR-afA-efR-afA-efV-afV-afV-afR-afV-afV-afV-afR-afA-gfA-gfW-afW-afW-cfW-afW-afW-cfW-afW-afW-cfW-afW-afW-cfW-afW-afW-ccS-Z-Z-Z-Z-Z-A,fw-afw-afw-afs-afw-afw-afw-afs-afw-afw-afw-afs-afw-afw-afw-afs-afb-gfb-gfs-afb-efs-afb-efs-afb-efs-afb-efw-afw-afw-afs-afw-afw-afw-afs-afb-gfb-gfx-afx-afx-cfx-afx-afx-cfx-afx-afx-cfx-afx-afx-cfx-afx-afx-cbX-Z-Z-Z-Z-Z-A,-pmr-aml-amr-amo-amr-aml-amr-amo-amq-ami-amq-amw-amq-ami-amq-amw-apu-gpu-gmw-amp-emw-amp-emr-aml-amr-amo-amr-aml-amr-amo-amq-ami-amq-amw-amq-ami-amq-amw-apu-omx-amx-amq-amw-amx-amx-amq-amB-amx-amx-amq-amw-amx-amx-amq-apu-Z-Z-Z-Z-Z-u\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<h2 id=\"park\">Park<\/h2>\n<hgroup class=\"punkomatic-song\" id=\"black-hole\">\n  <h3><a class=\"anchor\" href=\"#black-hole\" title=\"link to section\">#<\/a>Galaxy Slayers \u2014 Black Hole (Park 1)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Black Hole)-lcW-acD-aak-cak-cak-cak-cdf-ecB-aaP-gaP-gaf-gaf-ecD-aaf-gaf-ecD-adf-gdf-gdf-gdf-ccW-acD-aak-cak-cak-cak-cdf-ecB-aaP-gaP-gaf-gaf-ecD-aaf-gaf-ecD-aaf-gaf-ecD-aaf-gaf-ecD-adl-Z-Z-Z-Z-g,hI-ghI-ghJ-chJ-chJ-chJ-ciY-gda-cco-abieeda-cco-abieedc-cdv-cdc-ccq-adv-adc-cdv-cdc-ccq-adv-adl-gdl-ghI-ghI-ghJ-chJ-chJ-chJ-ciY-gda-cco-abieeda-cco-abieedc-cdv-cdc-ccq-adv-adc-cdv-cdc-ccq-adv-adc-cdv-cdc-ccq-adv-adc-cdv-cdc-ccq-adv-akt-Z-Z-Z-Z-g,hj-ghj-ghk-chk-chk-chk-ccc-cbC-aaOcOcc-cbC-aaOcOcc-cbC-aaOcOce-ccr-cce-cbE-acr-ace-ccr-cce-cbE-acr-ack-gck-ghj-ghj-ghk-chk-chk-chk-ccc-cbC-aaOcOcc-cbC-aaOcOcc-cbC-aaOcOce-ccr-cce-cbE-acr-ace-ccr-cce-cbE-acr-ace-ccr-cce-cbE-acr-ace-ccr-cce-cbE-acr-acj-Z-Z-Z-Z-g,hH-ghH-goL-coL-aow-aoL-coL-aow-aiY-gda-cco-abieeda-cco-abieeko-ckD-cko-cin-ajg-ako-ckD-cko-cin-ajg-akv-gkv-ghH-ghH-goL-coL-aow-aoL-coL-aow-aiY-gda-cco-abieeda-cco-abieeko-ckD-cko-cin-ajg-ako-ckD-cko-cin-ajg-aoJ-coZ-com-com-cko-ckD-cko-cin-ajg-aiW-Z-Z-Z-Z-g<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#black-hole\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Black Hole)-lcW-acD-aak-cak-cak-cak-cdf-ecB-aaP-gaP-gaf-gaf-ecD-aaf-gaf-ecD-adf-gdf-gdf-gdf-ccW-acD-aak-cak-cak-cak-cdf-ecB-aaP-gaP-gaf-gaf-ecD-aaf-gaf-ecD-aaf-gaf-ecD-aaf-gaf-ecD-adl-Z-Z-Z-Z-g,hI-ghI-ghJ-chJ-chJ-chJ-ciY-gda-cco-abieeda-cco-abieedc-cdv-cdc-ccq-adv-adc-cdv-cdc-ccq-adv-adl-gdl-ghI-ghI-ghJ-chJ-chJ-chJ-ciY-gda-cco-abieeda-cco-abieedc-cdv-cdc-ccq-adv-adc-cdv-cdc-ccq-adv-adc-cdv-cdc-ccq-adv-adc-cdv-cdc-ccq-adv-akt-Z-Z-Z-Z-g,hj-ghj-ghk-chk-chk-chk-ccc-cbC-aaOcOcc-cbC-aaOcOcc-cbC-aaOcOce-ccr-cce-cbE-acr-ace-ccr-cce-cbE-acr-ack-gck-ghj-ghj-ghk-chk-chk-chk-ccc-cbC-aaOcOcc-cbC-aaOcOcc-cbC-aaOcOce-ccr-cce-cbE-acr-ace-ccr-cce-cbE-acr-ace-ccr-cce-cbE-acr-ace-ccr-cce-cbE-acr-acj-Z-Z-Z-Z-g,hH-ghH-goL-coL-aow-aoL-coL-aow-aiY-gda-cco-abieeda-cco-abieeko-ckD-cko-cin-ajg-ako-ckD-cko-cin-ajg-akv-gkv-ghH-ghH-goL-coL-aow-aoL-coL-aow-aiY-gda-cco-abieeda-cco-abieeko-ckD-cko-cin-ajg-ako-ckD-cko-cin-ajg-aoJ-coZ-com-com-cko-ckD-cko-cin-ajg-aiW-Z-Z-Z-Z-g\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"the-scumdogs-return\">\n  <h3><a class=\"anchor\" href=\"#the-scumdogs-return\" title=\"link to section\">#<\/a>The Afro Anarchists \u2014 The Scumdogs Return (Park 2)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(The Scumdogs Return)df-adfdfdf-acO-adf-adfdfdf-acD-aaC-gaC-gaC-gdi-adi-adi-adi-aaC-gaC-gbw-gbw-gdi-adi-adi-adi-abN-gbN-hcE-aaC-gaC-gdidididididididididididididididiaD-gaD-ecB-gcD-abw-gbw-gbw-gbw-gdfcP-bdfcP-bbF-gbF-gau-gau-gau-gau-gdi-adi-adi-adi-aaC-gaC-gbw-gbw-gbw-gbw-gbw-gbw-abw-aahahahahdi-adi-adi-adi-aaC-gaC-gbF-gbF-gbw-gbw-gcP-ccP-cbH-gbH-gdf-fcEbK-hcE-abx-gbx-gdi-a,ap-abucScz-cap-abucScz-aaI-agt-cgt-cgt-cgt-cgt-cgt-can-aan-aan-aan-aad-cad-cad-cad-cgD-cgD-cgD-cgD-can-aan-aan-aan-agS-cgS-bcugS-cgS-bcu-cgt-bckgt-bcDgt-bckgt-bcDal-cal-cal-cal-cal-cal-cal-cal-cgN-cgN-cgN-cgN-abf-agN-cgN-abf-agN-cgN-abf-agN-cgN-abf-agL-cgL-cgL-cgL-bbRgL-cgL-bbRgK-ggK-fbigK-ggK-fadan-aan-aan-aan-aad-cad-cad-cad-cah-cah-caA-abm-abY-cah-cah-caA-abm-abY-acr-acr-ccr-ccr-acr-acrcrcrcran-aan-aan-aan-aad-cad-cad-cad-cgS-cgS-bckgS-cgS-bckbR-bbfbR-bckbR-bbfbR-bckgy-cgy-bczgy-cgy-bczgy-cgy-bczgE-cgH-bawgE-cgH-baw-cgo-cgo-bowgo-cgo-bowan-a,ak-aaXbXbK-cak-aaXbXbK-aax-afU-cfU-cfU-cfU-cfU-cfU-caj-aaj-aaj-aaj-aab-cab-cab-cab-cge-cge-cge-cge-caj-aaj-aaj-aaj-agt-cgt-bbGgt-cgt-bbG-cfU-bbAfU-bbNfU-bbAfU-bbNah-cah-cah-cah-cah-cah-cah-cah-cgo-cgo-cgo-cgo-aaN-ago-cgo-aaN-ago-cgo-aaN-ago-cgo-aaN-a!!-cgm-cgm-cgm-bbngm-cgm-bbngl-ggl-faOgl-ggl-fabaj-aaj-aaj-aaj-aab-cab-cab-cab-caf-caf-cas-aaS-abs-caf-caf-cas-aaS-abs-abF-abF-cbF-cbF-abF-abFbFbFbFaj-aaj-aaj-aaj-aab-cab-cab-cab-cgt-cgt-bbAgt-cgt-bbAbn-baNbn-bbAbn-baNbn-bbA!!-cfZ-bbKfZ-cfZ-bbKfZ-cfZ-bbK!!-ggf-cgi-bao-cfP-cfP-bbAfP-cfP-bbAaj-a,ap-abucScz-cap-abucScz-aaI-aif-cif-ckc-cjN-ckc-cjN-cke-ajP-ake-ajP-ajUjFiMjFjU-ajF-ajUjFiMjFjU-ajF-anp-cnt-cnp-cnt-cke-ajP-ake-ajP-agS-cgS-bcugS-cgS-bjM-cifkgjR-aifjRkg-aifkgjR-aifjRkgkbkc-cjN-ckc-cjN-ckc-bkbjN-bjMkc-bkbjN-bjMnB-cnx-cnw-cnx-anV-apr-cpc-anE-anD-clM-ant-alD-cnq-ahl-a!!-ggL-cgL-bbRgL-cgL-bbRgK-ggK-fbigK-ggK-fadke-ajP-ake-ajP-ajUjFiMjFjUkbjFjMjUjFiMjFjUkbjFjMahbmaTaAahbmaTkain-aiR-ajv-cmV-cmY-anp-alD-cmL-cjN-bjjjN-bjjjN-ajj-ajPjPjPjMke-ajP-ake-ajP-ajUjFiMjFjU-ajF-ajUjFiMjFjU-ajF-agS-cgS-bckgS-cgS-bckbR-bbfbR-bckbR-bbfbR-bck!!-fcznk-cnp-ant-anh-ans-anm-anj-agE-cgH-bawgE-cgH-baw-cgo-cgo-bowgo-cgo-bowan-a<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#the-scumdogs-return\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(The Scumdogs Return)df-adfdfdf-acO-adf-adfdfdf-acD-aaC-gaC-gaC-gdi-adi-adi-adi-aaC-gaC-gbw-gbw-gdi-adi-adi-adi-abN-gbN-hcE-aaC-gaC-gdidididididididididididididididiaD-gaD-ecB-gcD-abw-gbw-gbw-gbw-gdfcP-bdfcP-bbF-gbF-gau-gau-gau-gau-gdi-adi-adi-adi-aaC-gaC-gbw-gbw-gbw-gbw-gbw-gbw-abw-aahahahahdi-adi-adi-adi-aaC-gaC-gbF-gbF-gbw-gbw-gcP-ccP-cbH-gbH-gdf-fcEbK-hcE-abx-gbx-gdi-a,ap-abucScz-cap-abucScz-aaI-agt-cgt-cgt-cgt-cgt-cgt-can-aan-aan-aan-aad-cad-cad-cad-cgD-cgD-cgD-cgD-can-aan-aan-aan-agS-cgS-bcugS-cgS-bcu-cgt-bckgt-bcDgt-bckgt-bcDal-cal-cal-cal-cal-cal-cal-cal-cgN-cgN-cgN-cgN-abf-agN-cgN-abf-agN-cgN-abf-agN-cgN-abf-agL-cgL-cgL-cgL-bbRgL-cgL-bbRgK-ggK-fbigK-ggK-fadan-aan-aan-aan-aad-cad-cad-cad-cah-cah-caA-abm-abY-cah-cah-caA-abm-abY-acr-acr-ccr-ccr-acr-acrcrcrcran-aan-aan-aan-aad-cad-cad-cad-cgS-cgS-bckgS-cgS-bckbR-bbfbR-bckbR-bbfbR-bckgy-cgy-bczgy-cgy-bczgy-cgy-bczgE-cgH-bawgE-cgH-baw-cgo-cgo-bowgo-cgo-bowan-a,ak-aaXbXbK-cak-aaXbXbK-aax-afU-cfU-cfU-cfU-cfU-cfU-caj-aaj-aaj-aaj-aab-cab-cab-cab-cge-cge-cge-cge-caj-aaj-aaj-aaj-agt-cgt-bbGgt-cgt-bbG-cfU-bbAfU-bbNfU-bbAfU-bbNah-cah-cah-cah-cah-cah-cah-cah-cgo-cgo-cgo-cgo-aaN-ago-cgo-aaN-ago-cgo-aaN-ago-cgo-aaN-a!!-cgm-cgm-cgm-bbngm-cgm-bbngl-ggl-faOgl-ggl-fabaj-aaj-aaj-aaj-aab-cab-cab-cab-caf-caf-cas-aaS-abs-caf-caf-cas-aaS-abs-abF-abF-cbF-cbF-abF-abFbFbFbFaj-aaj-aaj-aaj-aab-cab-cab-cab-cgt-cgt-bbAgt-cgt-bbAbn-baNbn-bbAbn-baNbn-bbA!!-cfZ-bbKfZ-cfZ-bbKfZ-cfZ-bbK!!-ggf-cgi-bao-cfP-cfP-bbAfP-cfP-bbAaj-a,ap-abucScz-cap-abucScz-aaI-aif-cif-ckc-cjN-ckc-cjN-cke-ajP-ake-ajP-ajUjFiMjFjU-ajF-ajUjFiMjFjU-ajF-anp-cnt-cnp-cnt-cke-ajP-ake-ajP-agS-cgS-bcugS-cgS-bjM-cifkgjR-aifjRkg-aifkgjR-aifjRkgkbkc-cjN-ckc-cjN-ckc-bkbjN-bjMkc-bkbjN-bjMnB-cnx-cnw-cnx-anV-apr-cpc-anE-anD-clM-ant-alD-cnq-ahl-a!!-ggL-cgL-bbRgL-cgL-bbRgK-ggK-fbigK-ggK-fadke-ajP-ake-ajP-ajUjFiMjFjUkbjFjMjUjFiMjFjUkbjFjMahbmaTaAahbmaTkain-aiR-ajv-cmV-cmY-anp-alD-cmL-cjN-bjjjN-bjjjN-ajj-ajPjPjPjMke-ajP-ake-ajP-ajUjFiMjFjU-ajF-ajUjFiMjFjU-ajF-agS-cgS-bckgS-cgS-bckbR-bbfbR-bckbR-bbfbR-bck!!-fcznk-cnp-ant-anh-ans-anm-anj-agE-cgH-bawgE-cgH-baw-cgo-cgo-bowgo-cgo-bowan-a\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"we-will-grind-you\">\n  <h3><a class=\"anchor\" href=\"#we-will-grind-you\" title=\"link to section\">#<\/a>Those Who Died \u2014 We Will Grind You (Park 3)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(We Will Grind You)dgdgdgcBdgdgdgcBcQ-bcBcQ-acB-abz-fcBbz-ecB-abE-fcBbE-ecB-acQ-ccQ-ccB-acB-acBcBcF-abC-fcBbC-ecB-abl-cbl-cbl-cbl-adg-abD-ecBcBbD-ecBcBbE-ecBcBbE-ecBcBbC-gbC-acB-adf-acB-adf-acB-aaX-caX-caX-caX-cba-cba-cba-cba-acB-abz-gbz-ecF-acz-acz-acz-ccB-acB-acC-acD-adf-acB-adf-acB-aaX-ccC-acE-adf-Z-Z-Z-Z-c,cS-acScW!!cS-ackcScScScWcScSpm-acD-bcWcD-ack-acD-bcWcD-ack-acD-bcWcD-ack-acD-bcWcD-ack-acS-gcS-acS-acScSpm-acD-ccD-adIcWcD-ccD-adIcWcS-bbucS-bdXcS-bbucS-adV-acD-bbfcD-bdIcD-bbfcD-bdIcD-bbfcD-bdIcD-bbfcD-bdIdI-acW-acD-cdI-acW-acQ-adIcWcQ-adIcWcD-ccD-ccD-ccD-ccD-adIcWcD-adIcWcD-adIcWcD-adI-adI-acW-acD-cdI-acW-acD-cdI-acW-acD-cdI-acW-acD-ccQ-adIcWcQ-adIcWcS-adIcWcS-adIcWcQ-Z-Z-Z-Z-c,-hbX-cbX-cbN-cbN-cbN-cbN-cbN-cbN-cbN-cbN-ahu-a!!-gbX-abX-abXbXbX-abN-cbN-acAcabN-cbN-acAcabX-baXbX-bcKbX-baXbX-acJ-abN-baNbN-bcAbN-baNbN-bcAbN-baNbN-bcAbN-baNbN-bcAcA-aca-abN-ccA-aca-abW-acAcabW-acAcabN-acAcabN-acAcabN-acAcabN-acAcabN-acAcabN-acAcabN-acAcabN-acA-acA-aca-abN-ccA-aca-abN-ccA-aca-abN-ccA-aca-abN-cbW-acAcabW-acAcabX-acAcabX-acAcabW-Z-Z-Z-Z-c,-acS-acWcS-acS-aiC-biQiC-aiJiumf-cmf-aiMixmf-cmf-aiMixmf-cmf-aiMixmf-cmf-aiMixiA-ciQiBhXiQiA-ciQiBhXiQix-ciMixhTiMix-ciMixhTiMmm-gmm-gmm-ejUjqmm-eiMixmm-ejUjqmm-eiMixix-ahTiMix-cix-ahTiM!!-epm-akg-cjR-ckg-cjR-cjU-cjF-cjU-cjF-apm-aix-ahTiMix-cix-ahTiMix-cix-ahTiMix-cix-ahTiMix-kiB-ciB-apm-ake-Z-Z-Z-Z-c<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#we-will-grind-you\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(We Will Grind You)dgdgdgcBdgdgdgcBcQ-bcBcQ-acB-abz-fcBbz-ecB-abE-fcBbE-ecB-acQ-ccQ-ccB-acB-acBcBcF-abC-fcBbC-ecB-abl-cbl-cbl-cbl-adg-abD-ecBcBbD-ecBcBbE-ecBcBbE-ecBcBbC-gbC-acB-adf-acB-adf-acB-aaX-caX-caX-caX-cba-cba-cba-cba-acB-abz-gbz-ecF-acz-acz-acz-ccB-acB-acC-acD-adf-acB-adf-acB-aaX-ccC-acE-adf-Z-Z-Z-Z-c,cS-acScW!!cS-ackcScScScWcScSpm-acD-bcWcD-ack-acD-bcWcD-ack-acD-bcWcD-ack-acD-bcWcD-ack-acS-gcS-acS-acScSpm-acD-ccD-adIcWcD-ccD-adIcWcS-bbucS-bdXcS-bbucS-adV-acD-bbfcD-bdIcD-bbfcD-bdIcD-bbfcD-bdIcD-bbfcD-bdIdI-acW-acD-cdI-acW-acQ-adIcWcQ-adIcWcD-ccD-ccD-ccD-ccD-adIcWcD-adIcWcD-adIcWcD-adI-adI-acW-acD-cdI-acW-acD-cdI-acW-acD-cdI-acW-acD-ccQ-adIcWcQ-adIcWcS-adIcWcS-adIcWcQ-Z-Z-Z-Z-c,-hbX-cbX-cbN-cbN-cbN-cbN-cbN-cbN-cbN-cbN-ahu-a!!-gbX-abX-abXbXbX-abN-cbN-acAcabN-cbN-acAcabX-baXbX-bcKbX-baXbX-acJ-abN-baNbN-bcAbN-baNbN-bcAbN-baNbN-bcAbN-baNbN-bcAcA-aca-abN-ccA-aca-abW-acAcabW-acAcabN-acAcabN-acAcabN-acAcabN-acAcabN-acAcabN-acAcabN-acAcabN-acA-acA-aca-abN-ccA-aca-abN-ccA-aca-abN-ccA-aca-abN-cbW-acAcabW-acAcabX-acAcabX-acAcabW-Z-Z-Z-Z-c,-acS-acWcS-acS-aiC-biQiC-aiJiumf-cmf-aiMixmf-cmf-aiMixmf-cmf-aiMixmf-cmf-aiMixiA-ciQiBhXiQiA-ciQiBhXiQix-ciMixhTiMix-ciMixhTiMmm-gmm-gmm-ejUjqmm-eiMixmm-ejUjqmm-eiMixix-ahTiMix-cix-ahTiM!!-epm-akg-cjR-ckg-cjR-cjU-cjF-cjU-cjF-apm-aix-ahTiMix-cix-ahTiMix-cix-ahTiMix-cix-ahTiMix-kiB-ciB-apm-ake-Z-Z-Z-Z-c\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"tornadic\">\n  <h3><a class=\"anchor\" href=\"#tornadic\" title=\"link to section\">#<\/a>Impending Shadows \u2014 Tornadic (Park 4)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(Tornadic)-hdf-cdf-adf-adf-cdf-acH-acK-ccK-acK-acK-ccK-acKcKak-cak-cak-cak-acB-acB-acB-acB-acB-acB-acB-acB-acA-abz-gbz-ecB-abA-cbA-abA-abA-ccB-acC-abE-gbE-ecB-abE-gbE-ccE-acE-acL-ccL-ccL-ccL-ccL-ccL-ccL-ccC-acC-aab-cab-cab-aab-aab-acB-aag-cag-cag-aag-acB-acB-abb-cbb-cbb-cbb-acC-acB-acB-acB-acB-acB-acB-acB-adhdsbE-gbE-gbE-gbE-ecC-aaT-caT-caT-caT-acB-abE-gbE-ecC-acB-acB-acB-acC-acB-acD-adf-Z-Z-A,-bbd-ebb-ccg-aap-abb-cdX-aap-abb-ccg-aap-abb-cdX-apm-adI-aaa-aaM-cdI-aaa-aaM-aaa-adI-aaa-aaM-cdI-aaa-aaM-caM-cbR-aaa-aaM-cdI-aaa-aaM-cbR-aaa-aaM-cdI-aaa-adI-aaa-aaM-cdI-aaa-aaM-aaa-adI-aaa-aaM-cdI-aaa-aaM-caO-caO-cbT-aac-aaO-caO-caO-cbT-aac-aaO-caM-caM-cbR-aaa-aaM-caM-caM-cbR-aaa-aaM-caR-caz-caR-abD-aaz-caR-caz-caR-abD-aaz-aaG-aaM-cat-caM-aby-aat-caM-cat-caM-aby-aat-caM-cbR-aaa-aaM-cdI-aeu-adI-aaa-aaM-cdI-aaa-aaM-aaa-adI-aaa-aaM-cdI-aaa-abb-Z-Z-A,aM-gaK-cbx-aak-aaK-ccK-aak-aaK-cbx-aak-aaK-ccK-aak-acA-aaa-aaA-ccA-aaa-aaA-aaa-acA-aaa-aaA-ccA-aaa-aaA-caA-cbn-aaa-aaA-ccA-aaa-aaA-cbn-aaa-aaA-ccA-aaa-acA-aaa-aaA-ccA-aaa-aaA-aaa-acA-aaa-aaA-ccA-aaa-aaA-EaK-aaK-aaA-caA-cbn-aaa-aaA-caA-caA-cbn-aaa-aaA-saD-car-caD-abd-aar-aaw-aaA-can-caA-aba-aan-caA-can-caA-aba-aan-caA-cbn-aaa-aaA-ccA-ada-acA-aaa-aaA-ccA-aaa-aaA-aaa-acA-aaa-aaA-ccA-aaa-aaK-Z-Z-A,-diL-cnu-gnu-gnu-gnu-gjq-ajb-ahT-aix-ajq-ajb-aix-ahT-ajq-ajb-ahT-aix-ajq-ajb-aix-apm-anu-gnu-gnu-gnu-ckN-ahT-ajq-ajb-ahT-aix-ajq-ajb-aix-ahT-ajq-ajb-ahT-aix-ajq-ajb-aix-oiK-ciA-ciA-cjt-aje-aiA-cix-cix-cjq-ajb-aix-cix-cix-cjq-ajb-aix-siD-cio-ciD-ajh-aio-ais-aix-cii-cix-ajb-aii-cix-cii-cix-ajb-aii-cnu-gnu-gjq-ajb-ahT-aix-ajq-ajb-aix-ahT-ajq-ajb-ahT-aix-ajq-ajb-aiJ-Z-Z-A<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#tornadic\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(Tornadic)-hdf-cdf-adf-adf-cdf-acH-acK-ccK-acK-acK-ccK-acKcKak-cak-cak-cak-acB-acB-acB-acB-acB-acB-acB-acB-acA-abz-gbz-ecB-abA-cbA-abA-abA-ccB-acC-abE-gbE-ecB-abE-gbE-ccE-acE-acL-ccL-ccL-ccL-ccL-ccL-ccL-ccC-acC-aab-cab-cab-aab-aab-acB-aag-cag-cag-aag-acB-acB-abb-cbb-cbb-cbb-acC-acB-acB-acB-acB-acB-acB-acB-adhdsbE-gbE-gbE-gbE-ecC-aaT-caT-caT-caT-acB-abE-gbE-ecC-acB-acB-acB-acC-acB-acD-adf-Z-Z-A,-bbd-ebb-ccg-aap-abb-cdX-aap-abb-ccg-aap-abb-cdX-apm-adI-aaa-aaM-cdI-aaa-aaM-aaa-adI-aaa-aaM-cdI-aaa-aaM-caM-cbR-aaa-aaM-cdI-aaa-aaM-cbR-aaa-aaM-cdI-aaa-adI-aaa-aaM-cdI-aaa-aaM-aaa-adI-aaa-aaM-cdI-aaa-aaM-caO-caO-cbT-aac-aaO-caO-caO-cbT-aac-aaO-caM-caM-cbR-aaa-aaM-caM-caM-cbR-aaa-aaM-caR-caz-caR-abD-aaz-caR-caz-caR-abD-aaz-aaG-aaM-cat-caM-aby-aat-caM-cat-caM-aby-aat-caM-cbR-aaa-aaM-cdI-aeu-adI-aaa-aaM-cdI-aaa-aaM-aaa-adI-aaa-aaM-cdI-aaa-abb-Z-Z-A,aM-gaK-cbx-aak-aaK-ccK-aak-aaK-cbx-aak-aaK-ccK-aak-acA-aaa-aaA-ccA-aaa-aaA-aaa-acA-aaa-aaA-ccA-aaa-aaA-caA-cbn-aaa-aaA-ccA-aaa-aaA-cbn-aaa-aaA-ccA-aaa-acA-aaa-aaA-ccA-aaa-aaA-aaa-acA-aaa-aaA-ccA-aaa-aaA-EaK-aaK-aaA-caA-cbn-aaa-aaA-caA-caA-cbn-aaa-aaA-saD-car-caD-abd-aar-aaw-aaA-can-caA-aba-aan-caA-can-caA-aba-aan-caA-cbn-aaa-aaA-ccA-ada-acA-aaa-aaA-ccA-aaa-aaA-aaa-acA-aaa-aaA-ccA-aaa-aaK-Z-Z-A,-diL-cnu-gnu-gnu-gnu-gjq-ajb-ahT-aix-ajq-ajb-aix-ahT-ajq-ajb-ahT-aix-ajq-ajb-aix-apm-anu-gnu-gnu-gnu-ckN-ahT-ajq-ajb-ahT-aix-ajq-ajb-aix-ahT-ajq-ajb-ahT-aix-ajq-ajb-aix-oiK-ciA-ciA-cjt-aje-aiA-cix-cix-cjq-ajb-aix-cix-cix-cjq-ajb-aix-siD-cio-ciD-ajh-aio-ais-aix-cii-cix-ajb-aii-cix-cii-cix-ajb-aii-cnu-gnu-gjq-ajb-ahT-aix-ajq-ajb-aix-ahT-ajq-ajb-ahT-aix-ajq-ajb-aiJ-Z-Z-A\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n<hgroup class=\"punkomatic-song\" id=\"on-your-knees\">\n  <h3><a class=\"anchor\" href=\"#on-your-knees\" title=\"link to section\">#<\/a>The Dutchies \u2014 On Your Knees! (Park 5)<\/h3>\n  \n    <ul class=\"horizontal\">\n      \n      \n      \n      \n    <\/ul>\n  \n  <div class=\"row\">\n    <button id=\"play\" title=\"Play or download\" disabled>Play<\/button>\n    <button id=\"copy\" class=\"if-js\" title=\"Copy data\">Copy<\/button>\n    <pre><code>(On Your Knees!)didu-bao-cao-cao-caq-cas-cdf-aaq-caq-cas-caq-caq-cas-cas-cas-cab-gab-gaf-gaf-ecB-aag-gag-ecB-aag-ecC-aaJ-gaJ-acC-acz-caa-gaa-gae-gae-ecC-aaG-ecD-adg-Z-Z-Z-Z-Z-i,bsbv-bbs-cjK-cjv-ciR-ciR-ciY-aiW-ciM-ajF-aii-ciW-ciM-ajF-ajq-biMiM-biijq-biiiR-cin-clh-cko-ciR-cin-clh-cko-apm-alg-cim-cog-ckn-akjkNlg-cim-cop-cor-coo-cjJ-aju-aiY-glo-giQ-aiT-aim-aip-alg-alj-akn-apm-aiN-ciN-cbt-Z-Z-Z-Z-Z-i,aWaY-baW-caX-gaR-caR-caX-aaR-caR-car-caR-caR-cdr-ccR-cdr-cdR-cdr-ccR-cce-cdR-cdr-ccR-cce-ccQ-cdq-cdQ-ccd-acfcFcQ-cdq-cdQ-ccd-ccQ-cdq-cdN-cdn-ccN-cca-caN-can-ccN-cca-caN-caN-caW-Z-Z-Z-Z-Z-i,iR-ciR-ciR-ciR-cbl-cpn-cbu-abs-gkj-cbs-gkj-cjF-ckj-ciR-ciR-ciR-ciR-ajv-ajK-cjK-cjK-cjK-ajv-aeg-ceS-cbk-cdb-adddPeg-ceS-cbk-cdb-ceg-ceS-cbu-geq-gbg-cau-cec-ccX-cbg-cbg-cbt-Z-Z-Z-Z-Z-i<\/code><\/pre>\n  <\/div>\n  <div id=\"audio\" class=\"row\"><\/div>\n<\/hgroup>\n\n<style>\n  .punkomatic-song .row {\n    display: flex;\n    flex-flow: row nowrap;\n  }\n\n  .punkomatic-song .row button {\n    margin-right: 5px;\n    min-width: 72px;\n    max-width: 72px;\n    padding: 5px;\n  }\n\n  .punkomatic-song audio {\n    width: 100%;\n  }\n\n  .punkomatic-song pre > code {\n    user-select: all;\n  }\n<\/style>\n\n<script type=\"module\">\n  import * as pm from \"\/punkomatic-0.5.4.js\";\n\n  const songDiv = document.querySelector(\".punkomatic-song#on-your-knees\");\n\n  const playButton = songDiv.querySelector(\"button#play\");\n  const copyButton = songDiv.querySelector(\"button#copy\");\n  const codeElt = songDiv.querySelector(\"code\");\n  const audioDiv = songDiv.querySelector(\"#audio\");\n\n  copyButton.onclick = async () => {\n    await navigator.clipboard.writeText(codeElt.innerHTML);\n    copyButton.innerText = \"Done!\";\n    setTimeout(() => (copyButton.innerText = \"Copy\"), 2000);\n  };\n\n  playButton.disabled = false;\n  playButton.onclick = async () => {\n    playButton.onclick = null;\n\n    audioDiv.innerText = \"parsing song data...\";\n    const song = pm.parseSong(\"(On Your Knees!)didu-bao-cao-cao-caq-cas-cdf-aaq-caq-cas-caq-caq-cas-cas-cas-cab-gab-gaf-gaf-ecB-aag-gag-ecB-aag-ecC-aaJ-gaJ-acC-acz-caa-gaa-gae-gae-ecC-aaG-ecD-adg-Z-Z-Z-Z-Z-i,bsbv-bbs-cjK-cjv-ciR-ciR-ciY-aiW-ciM-ajF-aii-ciW-ciM-ajF-ajq-biMiM-biijq-biiiR-cin-clh-cko-ciR-cin-clh-cko-apm-alg-cim-cog-ckn-akjkNlg-cim-cop-cor-coo-cjJ-aju-aiY-glo-giQ-aiT-aim-aip-alg-alj-akn-apm-aiN-ciN-cbt-Z-Z-Z-Z-Z-i,aWaY-baW-caX-gaR-caR-caX-aaR-caR-car-caR-caR-cdr-ccR-cdr-cdR-cdr-ccR-cce-cdR-cdr-ccR-cce-ccQ-cdq-cdQ-ccd-acfcFcQ-cdq-cdQ-ccd-ccQ-cdq-cdN-cdn-ccN-cca-caN-can-ccN-cca-caN-caN-caW-Z-Z-Z-Z-Z-i,iR-ciR-ciR-ciR-cbl-cpn-cbu-abs-gkj-cbs-gkj-cjF-ckj-ciR-ciR-ciR-ciR-ajv-ajK-cjK-cjK-cjK-ajv-aeg-ceS-cbk-cdb-adddPeg-ceS-cbk-cdb-ceg-ceS-cbu-geq-gbg-cau-cec-ccX-cbg-cbg-cbt-Z-Z-Z-Z-Z-i\");\n\n    audioDiv.innerText = \"rendering song...\";\n    const audio = await pm.renderSong(song, {\n      baseSoundPath: \"\/punkomatic-samples\",\n      onprogress: (c, t) => {\n        audioDiv.innerText = `rendering song... ${((100 * c) \/ t).toFixed(2)}% done`;\n      },\n    });\n\n    audioDiv.innerText = \"encoding song...\";\n    const file = await pm.encodeSong(song, audio);\n\n    const audioElt = document.createElement(\"audio\");\n    audioElt.controls = true;\n    audioElt.src = URL.createObjectURL(file);\n    audioDiv.replaceChildren(audioElt);\n\n    playButton.onclick = () => audioElt.play();\n  };\n<\/script>\n"},{"title":"Reflection in JavaScript and TypeScript: writing a CLI framework","published":"2023-11-23T00:00:00+00:00","updated":"2023-11-23T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/js-ts-reflection-en\/"}},"id":"https:\/\/iliazeus.lol\/articles\/js-ts-reflection-en\/","content":"<p>Javascript, as most dynamically-typed languages, has a lot of ways to inspect its values at runtime - getting their types, querying object fields, constructors, prototypes, et cetera. In this article I will give an overview of such techniques, and then show how using TypeScript allows for even more powerful reflection using decorators and type metadata.<\/p>\n<p>I will demonstrate all of those by writing a toy CLI framework. By the end, its API will look something like this:<\/p>\n<img class=\"noborder\" src=\"cover.png\" alt=\"final CLI framework API\" \/>\n<p>I will structure this whole thing with \"levels\", starting with:<\/p>\n<h2 id=\"level-0-no-reflection\"><a class=\"anchor\" href=\"#level-0-no-reflection\" title=\"link to section\">#<\/a>Level 0: no reflection<\/h2>\n<p>To start, let's try to write our toy CLI framework without using any reflection at all. It will basically be a simple wrapper over Node's <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/nodejs.org\/docs\/latest-v20.x\/api\/util.html#utilparseargsconfig\"><code>util.parseArgs<\/code><\/a>.<\/p>\n<details><summary>stage0\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> Main<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> option is not specified<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> a boolean option, without a value<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> an option that has a value<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> an option specified multiple times<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">main<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Main<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-object z-property\"> positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-object z-property\"> values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>Using it will look something like this:<\/p>\n<details><summary>stage0\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">main<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> have to manually implement short options<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-keyword z-operator\"> ||<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">v<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> have to manually parse commands<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">commandArgs<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> args<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  switch<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    case<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">name<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> commandArgs<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">        console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">command required 1 argument, 0 given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> have to manually check option types<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">        console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    default<\/span><span class=\"z-punctuation\">:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>As you can see, this \"framework\" is extremely bare-bones. Short options, option value types, command dispatch - all of that has to be manually implemented. It's not a limitation of <code>parseArgs<\/code> - in fact, it accepts a detailed enough <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/nodejs.org\/docs\/latest-v20.x\/api\/util.html#utilparseargsconfig\">CLI definition<\/a> that has most of those features. The thing I want to do, though, is to generate all that automatically, using reflection.<\/p>\n<p>Anyway, let's start with the basics.<\/p>\n<h2 id=\"level-1-the-basics-of-js-reflection\"><a class=\"anchor\" href=\"#level-1-the-basics-of-js-reflection\" title=\"link to section\">#<\/a>Level 1: the basics of JS reflection<\/h2>\n<p>These things are basic enough that people usually don't event call them \"reflection\":<\/p>\n<ul>\n<li>\n<p><a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/typeof\">the <code>typeof<\/code> operator<\/a>: querying JS types of values<\/p>\n<p>The <code>typeof x<\/code> expression returns one of <code>\"undefined\"<\/code>, <code>\"boolean\"<\/code>, <code>\"number\"<\/code>, <code>\"bigint\"<\/code>, <code>\"string\"<\/code>, <code>\"object\"<\/code>, or <code>\"function\"<\/code>. One caveat is: <code>typeof null === \"object\"<\/code>, for historical reasons. Additionaly, it returns <code>\"function\"<\/code> for class constructors, even though they can only be called with <code>\"new\"<\/code>, and not as plain functions.<\/p>\n<\/li>\n<li>\n<p><a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/instanceof\">the <code>instanceof<\/code> operator<\/a>: querying an object's prototype chain<\/p>\n<p>Speaking in terms of class-based inheritance, <code>x instanceof A<\/code> returns <code>true<\/code> if <code>x<\/code> is an instance (duh) of <code>A<\/code> or any of its subclasses.<\/p>\n<\/li>\n<li>\n<p><a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/in\">the <code>in<\/code> operator<\/a>: querying whether an object has a property<\/p>\n<p>The <code>\"p\" in x<\/code> experssion returns <code>true<\/code> if <code>x<\/code> has a property named <code>p<\/code>. Note that <code>x<\/code> has to be an object - else a <code>TypeError<\/code> is thrown.<\/p>\n<\/li>\n<li>\n<p><a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/keys\">the <code>Object.keys()<\/code> function<\/a> and <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/for...in\">the <code>for...in<\/code> loop<\/a>: enumerating an object's properties<\/p>\n<p>Some of the properties might be non-<a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Enumerability_and_ownership_of_properties\">enumerable<\/a>, thus not showing up when using <code>Object.keys()<\/code> or <code>for...in<\/code>. Most \"regular\" object properties are enumerable, and I'll cover some exceptions later.<\/p>\n<\/li>\n<\/ul>\n<p>Let's apply some of the listed things to make our framework's API a little bit nicer. For example, let's make it so the program's entry point is a class, and its fields will represent command options:<\/p>\n<details><summary>stage1\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-object z-property\"> positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-object z-property\"> values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> by convention, all the fields of `program` represent CLI options<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> right now, those are shared between all commands<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> it&#39;s quite hard to write properly typed code when using reflection<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> so be prepared for some `any`s<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      (<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>The <code>main.ts<\/code> code now looks like this:<\/p>\n<details><summary>stage1\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> TypeScript&#39;s targets that are older than ES2022 won&#39;t have field definition syntax,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> which means that uninitialized field will be missing from the class,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> so I&#39;m explicitly initializing this to `undefined`<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-undefined z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> with a target of ES2022 or newer, you can just do:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  v<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> still have to manually implement short options<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">v<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> still have to manually dispatch commands<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">commandArgs<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> args<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    switch<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      case<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">name<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> commandArgs<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">          console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">command required 1 argument, 0 given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">          return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">        }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> still have to manually chech option types<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">          console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">          return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">        }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">        console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      default<\/span><span class=\"z-punctuation\">:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">        console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<p>Well, it does not look that much nicer as of right now. Commands, for example, still have to be dispatched manually. But we'll fix that with the next level of reflection!<\/p>\n<h2 id=\"level-2-object-prototypes-enumerating-methods\"><a class=\"anchor\" href=\"#level-2-object-prototypes-enumerating-methods\" title=\"link to section\">#<\/a>Level 2: object prototypes, enumerating methods<\/h2>\n<p>Let's make it so any method of <code>Program<\/code> is treated as a separate command.<\/p>\n<p>Insance methods in JavaScript are simply properties of its prototype, the values of which are functions. All objects of class <code>A<\/code> share the same prototype, which can be accessed as <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Function\/prototype\"><code>A.prototype<\/code><\/a>.<\/p>\n<p>Thing is, though, that those prototype properties are <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Functions\/Method_definitions#method_definitions_in_classes\">marked as non-enumerable<\/a>, meaning we can't just use <code>Object.keys()<\/code> or a <code>for...in<\/code> loop. For that, there is the <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/getOwnPropertyNames\"><code>Object.getOwnPropertyNames()<\/code><\/a> function. The <code>Own<\/code> in the name means that it will only return the keys of this exact object, not of its prototypes. Which means that in order to handle the methods of <code>Program<\/code>'s possible superclasses, we will have to walk the prototype chain ourselves - like this:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> allKeys<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> proto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-support z-class\"> A<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> proto<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> proto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getPrototypeOf<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">proto<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  allKeys<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-keyword z-operator\">...<\/span><span class=\"z-source\">Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">proto<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>For our toy example, though, let's simply say that only <code>Program<\/code>'s own methods will be treated as commands. And let's also not forget to filter out <code>constructor<\/code> from the list of the prototype's properties.<\/p>\n<details><summary>stage2\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> sharedOpts<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> sharedOpts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> by convention, all `program`&#39;s instance methods define separate commands<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> they are not enumerable, so we use getOwnPropertyNames() instead of keys()<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">filter<\/span><span class=\"z-source\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    (<\/span><span class=\"z-variable z-parameter\">k<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">function<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">constructor<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  )<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>This allows us to finally get rid of command dispatch code in <code>main.ts<\/code>:<\/p>\n<details><summary>stage2\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  v<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">v<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">name<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> args<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">command required 1 argument, 0 given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"level-3-function-arguments\"><a class=\"anchor\" href=\"#level-3-function-arguments\" title=\"link to section\">#<\/a>Level 3: function arguments<\/h2>\n<p>It would be nice to not have to parse the <code>args<\/code> ourselves, but instead to force the framework to do that and to validate the number of arguments. For that, we'll change the interface of command methods a bit, passing <code>args<\/code> as separate arguments, and putting the <code>opts<\/code> as the first argument:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> Before:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">hello<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">string<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">Record<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-variable z-other z-readwrite\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">: <\/span><span class=\"z-keyword z-operator\">...<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> After:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">hello<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">Record<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-variable z-other z-readwrite\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> name<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">string<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">: <\/span><span class=\"z-keyword z-operator\">...<\/span><\/span><\/code><\/pre>\n<p>This allows us to validate the number of CLI arguments based on the number of command functions' arguments - which can be queried by using the <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Function\/length\"><code>f.length<\/code> property<\/a>.<\/p>\n<p>There is a caveat, though. The <code>f.length<\/code> property is, in fact, a <em>minimum required<\/em> number of arguments! It does not count any optional arguments:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> arguments with a default value<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> f1<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">a<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> b<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">assert<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">f1<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> rest-arguments<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> f2<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">a<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-parameter\">bs<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">assert<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">f2<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> the `arguments` property<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> f3<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">a<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  doWork<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">arguments<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">2<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">assert<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">f3<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> and the &quot;extra&quot; arguments at call site<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> f4<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">a<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">f4<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 3<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 4<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 5<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>Being mindful of that, let's implement the validation of the <em>minimum<\/em> number of CLI arguments;<\/p>\n<details><summary>stage3\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> passing `args` as separate arguments<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> sharedOpts<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> sharedOpts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> by convention, all `program`&#39;s instance methods define separate commands<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> they are not enumerable, so we use getOwnPropertyNames() instead of keys()<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">filter<\/span><span class=\"z-source\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    (<\/span><span class=\"z-variable z-parameter\">k<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">function<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">constructor<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  )<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> the -1 is here because of the `opts` argument<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<details><summary>stage3\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  v<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">v<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"level-4-decorators-and-reflect-metadata\"><a class=\"anchor\" href=\"#level-4-decorators-and-reflect-metadata\" title=\"link to section\">#<\/a>Level 4: decorators and <code>Reflect.metadata<\/code><\/h2>\n<p>To make our framework understand short options, we need a way to specify those short names as additional metadata beside the option field, possibly with some extra option metadata. It will also allow us to explicitly mark option fields and command methods, allowing <code>Program<\/code> to have fields and options that aren't part of the CLI.<\/p>\n<p>The most convenient way to do that is to use decorators. In TypeScript, there actuall are two decorator implementations:<\/p>\n<ul>\n<li>the now-ECMAScript-standard one, available by default <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-0\/#decorators\">since TypeScript 5.0<\/a><\/li>\n<li>the one based on a previous draft, available using <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/decorators.html\">the <code>experimentalDecorators<\/code> option<\/a><\/li>\n<\/ul>\n<p>For one of the further reflection levels, we'll in fact have to use the \"older\" implementation. But for now, we can abstract those away completely using the <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/reflect-metadata\"><code>reflect-metadata<\/code><\/a> library:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> the global Reflect object now has some new methods<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Foo<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> you can use Reflect.metadata() itself as a decorator<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-meta z-decorator\">Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">meta-key<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">value<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  f<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> but it&#39;s better to wrap it into a function<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> MyDecorator<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">value<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> you can use this same function as a metadata key<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">MyDecorator<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> value<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Bar<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">MyDecorator<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">value<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> accessing the metadata<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> value1<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Foo<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">meta-key<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">f<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> value2<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Bar<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> MyDecorator<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">prop<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> if called without the last argument, it returns the metadata for the class itself,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> rather than its members<\/span><\/span><\/code><\/pre>\n<p>Let's implement the short options feature with decorators and <code>reflect-metadata<\/code>:<\/p>\n<details><summary>stage4\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  short<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> a Reflect.metadata-based decorator<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> you can use the function itself as metadata key<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Option<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">def<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> def<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> for convenience, let&#39;s also define a getter<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> even if the decorator has no arguments,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> it&#39;s more convenient to wrap it in a function anyway<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Command<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>The <code>main.ts<\/code> now looks like this:<\/p>\n<details><summary>stage4\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> specifying short options with a decorator<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">v<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> no @Option() decorator means this is not an option<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  version<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">1.0.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Command<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> for now, command-specific options still have to be handled manually<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"level-5-runtime-type-descriptors\"><a class=\"anchor\" href=\"#level-5-runtime-type-descriptors\" title=\"link to section\">#<\/a>Level 5: runtime type descriptors<\/h2>\n<p>The next logical step is for the <code>@Option()<\/code> decorator to also specify the type of the option's value. Thing is, JavaScript doesn't have a built-in way of representing types at runtime. There are the <code>typeof<\/code> values, of course - but they aren't really useful for arrays and objects, as they don't specify the types of elements and members.<\/p>\n<p>To combat that, there are a few common conventions. For example, <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.nestjs.com\/\">Nest.js<\/a>, among others, <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.nestjs.com\/openapi\/types-and-parameters#arrays\">often<\/a> <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.nestjs.com\/techniques\/mongodb#model-injection\">uses<\/a> these:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> primitive types are represented by their &quot;constructors&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> number<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> Number<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> string<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> arrays are representet by one-element arrays<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> arrayOfNumber<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Number<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> arrayOfString<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> objects are represented by, well, objects<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> person<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  name<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  age<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> Number<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> you can combine those in any way you like<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> dto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  people<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> name<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> age<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> Number<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> it often resembles actual TypeScript type definitions<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">type<\/span><span class=\"z-entity z-name z-type\"> Dto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  people<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-object z-property\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-object z-property\"> age<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>It is important to distinguish between these and the actual TypeScript types. For example, defining a field in a TypeScript interface as <code>Number<\/code> instead of <code>number<\/code> can lead to a non-obvious errors - a primitive type <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/play#code\/DYUwLgBAhgXBByBXAtgIxAJwgXggRgCYBmAbgChRJU4A7FdLXAFgFYA2csqHCVc1HlBJA\">can be assigned<\/a> to a boxed type variable, but not the other way around!<\/p>\n<p>Let's now use this \"type descriptor\" syntax to specify the types for our CLI options. We don't even have to implement the whole type hierarchy - <code>parseArgs<\/code> only supports <code>boolean<\/code>, <code>string<\/code>, <code>boolean[]<\/code> and <code>string[]<\/code>:<\/p>\n<details><summary>stage5\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> ParseArgsConfig<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  short<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  type<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Option<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">def<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> def<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Command<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> idk why, but this type isn&#39;t exported properly<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">type<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Exclude<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">ParseArgsConfig<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">options<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> config<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">Array<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">isArray<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    config<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> config<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<details><summary>stage5\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> type<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">v<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  version<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">1.0.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Command<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"level-6-making-typescript-do-the-work\"><a class=\"anchor\" href=\"#level-6-making-typescript-do-the-work\" title=\"link to section\">#<\/a>Level 6: making TypeScript do the work<\/h2>\n<p>When using TypeScript, it is possible to make it embed some type information into class member metadata. For that, we'll need:<\/p>\n<ul>\n<li>to enable the <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/tsconfig#emitDecoratorMetadata\"><code>emitDecoratorMetadata<\/code><\/a> compiler option;<\/li>\n<li>to enable \"older\" <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/tsconfig#experimentalDecorators\"><code>experimentalDecorators<\/code><\/a>;<\/li>\n<li>to use our old friend <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/reflect-metadata\"><code>reflect-metadata<\/code><\/a>.<\/li>\n<\/ul>\n<p>We need those older decorators specifically - the now-standard ones, sadly, won't work.<\/p>\n<p>The type metadata is only saved for class members, and only for those that have at least one decorator attached to them. The metadata format isn't well documented, but we can get an idea bu just <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/play?experimentalDecorators=true&amp;emitDecoratorMetadata=true&amp;target=9#code\/CYUwxgNghgTiAEYD2A7AzgF3gWQJ4BFwkYoNiAueAMQFcUwMBLVAbgCg3Io01qkl4AbzbxR8AAJ5CyEmRgixoGaRDAACjCQAHAISVMMRigDm7BaLpLiK9Zt36Mhk2bESpRWcXPwrs1dhAMAAskYAAKADN+Sip+ABp4FEoUGgBbACMQGABKBydjIW9XOAwaGBR4ACJuYAjK9lcAXzZGoA\">messing around<\/a> on the TS Playground.<\/p>\n<p>Sadly, the metadata isn't as detailed as I'd want it to be. In essence, each type is represented by its \"constructor\" function - <code>Number<\/code> for <code>number<\/code>, <code>Boolean<\/code> for <code>boolean<\/code>, et cetera. That means that any object type (that is not a class itself) is just <code>Object<\/code> and any array is just <code>Array<\/code> - without any info on the type of elements or members.<\/p>\n<p>All this means that TypeScript's type metadata is not enough to be the <em>only<\/em> source of type info for our options. But it <em>would<\/em> make the API nicer if we implement it as a possibility:<\/p>\n<details><summary>stage6\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> ParseArgsConfig<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  short<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  type<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Option<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">def<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> def<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Command<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">type<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Exclude<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">ParseArgsConfig<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">options<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> config<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> getting the TypeScript type metadata<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> defType<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">design:type<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">Array<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">isArray<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      throw<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unable to determine option type for <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    config<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> config<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<details><summary>stage6\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> you might have to specify the types explicitly for emitDecoratorMetadata to work<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> even in cases where they are inferred correctly by the compiler<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">v<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  version<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">1.0.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Command<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"level-7-method-argument-types-and-dto-classes\"><a class=\"anchor\" href=\"#level-7-method-argument-types-and-dto-classes\" title=\"link to section\">#<\/a>Level 7: method argument types and DTO classes<\/h2>\n<p>The same <code>emitDecoratorMetadata<\/code> feature will allow us to query types of class method arguments. We'll use that to finally get rid of the need to manually validate per-command options.<\/p>\n<p>But to overcome the metadata limitations, we'll need to introduce DTO classes for those options:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> instead of this:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">interface<\/span><span class=\"z-entity z-name z-type\"> IOptions<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  enthusiastic<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> we&#39;ll need this:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Options<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  enthusiastic<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> you can still use object literals with such types<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts1<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Options<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-source\"> enthusiastic<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts2<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Options<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-constant\"> JSON<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">parse<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">str<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> but remember that they won&#39;t magically become instances of Options!<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">assert<\/span><span class=\"z-source\">(<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts1<\/span><span class=\"z-keyword z-operator z-expression z-instanceof z-ts\"> instanceof<\/span><span class=\"z-entity z-name z-type\"> Options<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>Let's add this final feature to our framework.<\/p>\n<details><summary>stage7\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> ParseArgsConfig<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  short<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  type<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Option<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">def<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> def<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Command<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> OptsDto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">design:paramtypes<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> optsDto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> OptsDto<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> OptsDto<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-constant z-language z-undefined z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      ...<\/span><span class=\"z-entity z-name z-function\">getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      ...<\/span><span class=\"z-entity z-name z-function\">getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">OptsDto<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> optsDto<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">assign<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">optsDto<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">optsDto<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">type<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Exclude<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">ParseArgsConfig<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">options<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> config<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> defType<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">design:type<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">Array<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">isArray<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      throw<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unable to determine option type for <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    config<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> config<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> extractOptions<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Dto<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> dto<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">dto<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Dto<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      dto<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      dto<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>This is how our final API looks like in <code>main.ts<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043c\u043e\u0436\u043d\u043e \u0434\u0430\u0436\u0435 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043a\u0430\u043a abstract<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> HelloOptions<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  enthusiastic<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">v<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  version<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">1.0.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Command<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-parameter\"> enthusiastic<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> HelloOptions<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><h2 id=\"conclusion\"><a class=\"anchor\" href=\"#conclusion\" title=\"link to section\">#<\/a>@Conclusion()<\/h2>\n<p>As this last bit of code (hopefully) demonstrates, reflection is a very powerful tool for designing nice-to-use APIs. A lot of TypeScript frameworks use those - <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.nestjs.com\/\">Nest.js<\/a> being my primary inspiration. I hope this brief overview of reflection techniques was helpful!<\/p>\n"},{"title":"Exploring V8's strings: implementation and optimizations","published":"2023-11-14T00:00:00+00:00","updated":"2023-11-14T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/js-string-optimizations-en\/"}},"id":"https:\/\/iliazeus.lol\/articles\/js-string-optimizations-en\/","content":"<p>JavaScript was always, in one way or another, a text manipulation language - from early web page HTML to modern compilers and tooling. Not a surprise, then, that quite a lot of time was spent tuning and optimizing the string value handling in most modern JS engines.<\/p>\n<p>In this article, I will focus on V8's implementation of strings. I will demonstrate various string optimizations by beating C++ in a <em>totally 100% legit<\/em> benchmark. Finally, I will demonstrate the ways in which these implementation details might actually perform worse, and how to deal with that.<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/js-string-optimizations-en\/cover.png\" alt=\"beating C++, 100% totally legit\" \/><\/p>\n<h2 id=\"prerequisites\"><a class=\"anchor\" href=\"#prerequisites\" title=\"link to section\">#<\/a>Prerequisites<\/h2>\n<p>To be able to tell which string implementation V8 is using in any given moment, I will use V8's <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/v8\/v8\/blob\/941b945b\/src\/runtime\/runtime.h#L20\">debug intrinsics<\/a>. To be able to access those, run Node.js with an <code>--allow-natives-syntax<\/code> argument.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">$<\/span><span class=\"z-variable z-other z-readwrite\"> node<\/span><span class=\"z-keyword z-operator\"> --<\/span><span class=\"z-variable z-other z-readwrite\">allow<\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-variable z-other z-readwrite\">natives<\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-variable z-other z-readwrite\">syntax<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">Welcome<\/span><span class=\"z-variable z-other z-readwrite\"> to<\/span><span class=\"z-source\"> Node<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">js<\/span><span class=\"z-variable z-other z-readwrite\"> v20<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-constant z-numeric\">3<\/span><span class=\"z-constant z-numeric\">.<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation z-accessor\">.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">Type<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.help<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-variable z-other z-readwrite\"> for<\/span><span class=\"z-variable z-other z-readwrite\"> more<\/span><span class=\"z-variable z-other z-readwrite\"> information<\/span><span class=\"z-punctuation z-accessor\">.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">123<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-source\"> Smi<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x7b<\/span><span class=\"z-source\"> (<\/span><span class=\"z-constant z-numeric\">123<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">123<\/span><\/span><\/code><\/pre>\n<p>The <code>%DebugPrint()<\/code> intrinsic writes out quite a lot of info when used on strings. I will only show here the most important bits, using <code>\/* ... *\/<\/code> to skip over the others.<\/p>\n<h2 id=\"v8-s-string-implementations\"><a class=\"anchor\" href=\"#v8-s-string-implementations\" title=\"link to section\">#<\/a>V8's string implementations<\/h2>\n<p>Inside V8's source code, there's a <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/v8\/v8\/blob\/941b945b\/src\/objects\/objects.h#L134-L151\">handy list<\/a> of all the string implementations it uses:<\/p>\n<ul>\n<li><code>String<\/code>\n<ul>\n<li><code>SeqString<\/code>\n<ul>\n<li><code>SeqOneByteString<\/code><\/li>\n<li><code>SeqTwoByteString<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>SlicedString<\/code><\/li>\n<li><code>ConsString<\/code><\/li>\n<li><code>ThinString<\/code><\/li>\n<li><code>ExternalString<\/code>\n<ul>\n<li><code>ExternalOneByteString<\/code><\/li>\n<li><code>ExternalTwoByteString<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>InternalizedString<\/code>\n<ul>\n<li><code>SeqInternalizedString<\/code>\n<ul>\n<li><code>SeqOneByteInternalizedString<\/code><\/li>\n<li><code>SeqTwoByteInternalizedString<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>ConsInternalizedString<\/code><\/li>\n<li><code>ExternalInternalizedString<\/code>\n<ul>\n<li><code>ExternalOneByteInternalizedString<\/code><\/li>\n<li><code>ExternalTwoByteInternalizedString<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Most of those, however, are combinations of several base traits:<\/p>\n<h3 id=\"onebyte-vs-twobyte\"><a class=\"anchor\" href=\"#onebyte-vs-twobyte\" title=\"link to section\">#<\/a><code>OneByte<\/code> vs <code>TwoByte<\/code><\/h3>\n<p>The ECMAScript standard <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/262.ecma-international.org\/14.0\/#sec-ecmascript-language-types-string-type\">defines a string<\/a> as a sequence of 16-bit elements. But in a lot of cases, storing 2 bytes per character is a waste of memory. In fact, quite a lot of strings in most code will be limited to ASCII. That is why V8 has both one-byte and two-byte strings.<\/p>\n<p>Here is an example of an ASCII string. Notice its <code>type<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x209affbb9309<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-source\"> OldSpace<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-source\"> #<\/span><span class=\"z-variable z-other z-readwrite\">hello<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0x30f098a80299<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_INTERNALIZED_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre>\n<p>And here is a non-ASCII one. It has a two-byte representation:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">\u043f\u0440\u0438\u0432\u0435\u0442<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x1b10a9ba2291<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-source\"> OldSpace<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-readwrite\"> u<\/span><span class=\"z-source\">#\\<\/span><span class=\"z-variable z-other z-readwrite\">u043f<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0440<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0438<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0432<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0435<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0442<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0x30f098a81e29<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> INTERNALIZED_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre><h3 id=\"internalized\"><a class=\"anchor\" href=\"#internalized\" title=\"link to section\">#<\/a><code>Internalized<\/code><\/h3>\n<p>Some strings - string literals in particular - are <em>internalized<\/em> by the engine - that is, collected into a single string pool. Whenever you use a particular string literal, the internalized version from this pool is used, instead of allocating a new one every time. Such strings will have an <code>Internalized<\/code> type:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x209affbb9309<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-source\"> OldSpace<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-source\"> #<\/span><span class=\"z-variable z-other z-readwrite\">hello<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0x30f098a80299<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_INTERNALIZED_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre>\n<p>If a string value is only known at run time, it (usually) won't be internalized. Notice the absence of <code>INTERNALIZED<\/code> in its <code>type<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-storage z-type\"> var<\/span><span class=\"z-variable z-other z-readwrite\"> fs<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> require<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">fs<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writeFileSync<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">utf8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-storage z-type\"> var<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">readFileSync<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">utf8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">s<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x2c6f46782469<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec0879<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre>\n<p>It is worth noting that this string can still be internalized. You can force that by turning it into a string literal with <code>eval<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-storage z-type\"> var<\/span><span class=\"z-variable z-other z-readwrite\"> ss<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> eval<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-language z-undefined z-js\">undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">ss<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x80160fa1809<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-source\"> OldSpace<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-source\"> #<\/span><span class=\"z-variable z-other z-readwrite\">hello<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec0299<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_INTERNALIZED_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre><h3 id=\"external\"><a class=\"anchor\" href=\"#external\" title=\"link to section\">#<\/a><code>External<\/code><\/h3>\n<p><em>External<\/em> strings are the ones allocated outside JavaScript's heap. It is usually done for larger strings, to not move them around the memory at garbage collection. To demonstrate such a string, I will artificially limit V8's heap size, and then allocate a large string:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> test.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> a 16 megabyte string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">var<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Buffer<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">alloc<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">16<\/span><span class=\"z-keyword z-operator\"> *<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-keyword z-operator\"> *<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-constant z-numeric\"> 20<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 65<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toString<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">ascii<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> and an 8 megabyte heap<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=8<\/span><span class=\"z-string\"> test.js<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">16777216<\/span><\/span><\/code><\/pre><h3 id=\"sliced\"><a class=\"anchor\" href=\"#sliced\" title=\"link to section\">#<\/a><code>Sliced<\/code><\/h3>\n<p>Slicing a string in V8 does not actually copy the data most of the time. Instead, a <em>sliced<\/em> string is created, storing a reference to a parent string, an offset and a length. Other languages would call that a <em>string view<\/em> or a <em>string slice<\/em>.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-storage z-type\"> var<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Buffer<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">alloc<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">256<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 65<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toString<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-string\">ascii<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-language z-undefined z-js\">undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">slice<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 15<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x80e9bea9851<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">AAAAAAAAAAAAAAA<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec1d09<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> SLICED_ONE_BYTE_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre>\n<p>If, however, the substring is short enough, it's sometimes faster to just copy that tiny bit of data:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">slice<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 5<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x18a9c2e10169<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">AAAAA<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec0879<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre><h3 id=\"cons\"><a class=\"anchor\" href=\"#cons\" title=\"link to section\">#<\/a><code>Cons<\/code><\/h3>\n<p>String concatenation is optimized in a similar way. It yields a <code>Cons<\/code> string, which stores references to its left and right parts:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">s<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x2c6f467b3e09<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">c<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">AAAAAAAAAA\/* ... *\/AA<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec1be9<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> CONS_ONE_BYTE_STRING_TYPE<\/span><\/span><\/code><\/pre>\n<p>Again, shorter strings are usually just copied outright:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">slice<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-source\"> s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">slice<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 3<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0xec9b3412501<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">AAAAA<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec0879<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre><h2 id=\"beating-c-with-string-optimizations\"><a class=\"anchor\" href=\"#beating-c-with-string-optimizations\" title=\"link to section\">#<\/a>Beating C++ with string optimizations<\/h2>\n<p>Let's use all that we've learned so far to play a game of Unfair Benchmarks. The rules are simple: we have to think of a specific contrived task where JavaScript, because of its string optimizations, will be faster than the equivalent C++ code.<\/p>\n<p>In our case, we'll exploit the fact that <code>Cons<\/code> and <code>Sliced<\/code> string don't copy the data.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> unethical-benchmark.js<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> given an ASCII string of length 1500,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> find the total length of those of its substrings<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> that are longer than 200 chars<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> text<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">a<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">repeat<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">1500<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> result<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> j<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-constant z-numeric\"> 201<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> j<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> j<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    result<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">substr<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">i<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> j<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">result<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>We'll run it on bare V8 using <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/jsvu\">jsvu<\/a>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> time<\/span><span class=\"z-string\"> ~\/.jsvu\/bin\/v8<\/span><span class=\"z-string\"> unethical-benchmark.js<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">535036450<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">real<\/span><span class=\"z-string\">    0m0.145s<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">user<\/span><span class=\"z-string\">    0m0.122s<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">sys<\/span><span class=\"z-string\">     0m0.028s<\/span><\/span><\/code><\/pre>\n<p>And here is the C++ code, translated line-by-line:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> unethical-benchmark.cxx<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> given an ASCII string of length 1500,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> find the total length of those of its substrings<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> that are longer than 200 chars<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">include<\/span><span class=\"z-punctuation z-definition z-string\"> &lt;<\/span><span class=\"z-string\">iostream<\/span><span class=\"z-punctuation z-definition z-string\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">include<\/span><span class=\"z-punctuation z-definition z-string\"> &lt;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">int<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">  std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">string<\/span><span class=\"z-entity z-name z-function\"> text<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-constant z-numeric\">1500<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">a<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">  std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">string result<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-storage z-type\">int<\/span><span class=\"z-source\"> i <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-source\"> i <\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">length<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-source\"> i<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-storage z-type\">int<\/span><span class=\"z-source\"> j <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> i <\/span><span class=\"z-keyword z-operator\">+<\/span><span class=\"z-constant z-numeric\"> 201<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-source\"> j <\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">length<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-source\"> j<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      result <\/span><span class=\"z-keyword z-operator\">+=<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">substr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">i<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> j <\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-source\"> i<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">  std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">cout <\/span><span class=\"z-keyword z-operator\">&lt;&lt;<\/span><span class=\"z-source\"> result<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">length<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\"> &lt;&lt;<\/span><span class=\"z-entity z-name z-scope-resolution z-cpp\"> std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">endl<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> g++<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">O3<\/span><span class=\"z-string\"> unethical-benchmark.cxx<\/span><span class=\"z-punctuation\"> &amp;&amp;<\/span><span class=\"z-keyword\"> time<\/span><span class=\"z-source\"> .\/a.out<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">535036450<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">real<\/span><span class=\"z-string\">    0m0.324s<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">user<\/span><span class=\"z-string\">    0m0.176s<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">sys<\/span><span class=\"z-string\">     0m0.147s<\/span><\/span><\/code><\/pre>\n<p>This segment is, of course, a joke - both the code and the problem are obviously bad. But it succeeds demonstrating that even the most naive code can be sped up considerably by the V8's string optimizations.<\/p>\n<h2 id=\"unintended-side-effects-or-how-to-scrub-a-string\"><a class=\"anchor\" href=\"#unintended-side-effects-or-how-to-scrub-a-string\" title=\"link to section\">#<\/a>Unintended side effects, or: how to scrub a string<\/h2>\n<p>The downside of such implicit optimizations is, of course, that you can't really control them. In many other languages, a programmer can choose to explicitly use a string view or a string builder where they really need them. But JS has the programmer either hoping the engine is smart enough, or using black magic to force it to do what they want.<\/p>\n<p>To demonstrate one such case, I will first write a simple script that will fetch a couple of web pages, and then extract from them all the linked URLs:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> urls-1.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  ]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">pageUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">text<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-source\"> html<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">matchAll<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string z-begin\">\/<\/span><span class=\"z-string\">href=&quot;<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">(<\/span><span class=\"z-constant z-other z-character-class z-regexp\">.<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">*<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">?<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">)<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string z-end\">\/<\/span><span class=\"z-keyword\">g<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      linkUrls<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>Let's find out the smallest heap size it will run on:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=10<\/span><span class=\"z-string\"> urls-1.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><span class=\"z-punctuation z-definition z-comment\"> #<\/span><span class=\"z-comment\"> works<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=9<\/span><span class=\"z-string\"> urls-1.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- Last few GCs ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">252407:0x55b40628dbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     2894 ms: Mark-Compact 10.8 (<\/span><span class=\"z-entity z-name z-function\">13.7<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 8.5 (<\/span><span class=\"z-entity z-name z-function\">16.9<\/span><span class=\"z-source\">) MB, 9.22 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.989,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.683<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> scavenge<\/span><span class=\"z-string\"> might<\/span><span class=\"z-string\"> not<\/span><span class=\"z-string\"> succeed<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">252407:0x55b40628dbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     2906 ms: Mark-Compact (<\/span><span class=\"z-entity z-name z-function\">reduce<\/span><span class=\"z-source\">) 9.7 (<\/span><span class=\"z-entity z-name z-function\">16.9<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 9.1 (<\/span><span class=\"z-entity z-name z-function\">10.4<\/span><span class=\"z-source\">) MB, 2.68 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">+<\/span><span class=\"z-constant z-numeric\"> 0.9<\/span><span class=\"z-string\"> ms<\/span><span class=\"z-string\"> in<\/span><span class=\"z-constant z-numeric\"> 12<\/span><span class=\"z-string\"> steps<\/span><span class=\"z-string\"> since<\/span><span class=\"z-string\"> start<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> marking,<\/span><span class=\"z-string\"> biggest<\/span><span class=\"z-string\"> step<\/span><span class=\"z-constant z-numeric\"> 0.1<\/span><span class=\"z-string\"> ms,<\/span><span class=\"z-string\"> walltime<\/span><span class=\"z-string\"> since<\/span><span class=\"z-string\"> start<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> marking<\/span><span class=\"z-constant z-numeric\"> 10<\/span><span class=\"z-string\"> ms<\/span><span class=\"z-source\">) (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.984,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.681<\/span><span class=\"z-source\">) fina<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- JS stacktrace ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">FATAL<\/span><span class=\"z-string\"> ERROR:<\/span><span class=\"z-string\"> Reached<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> limit<\/span><span class=\"z-string\"> Allocation<\/span><span class=\"z-string\"> failed<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> JavaScript<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> out<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> memory<\/span><\/span><\/code><\/pre>\n<p>Looks like 10 megabytes is enough, but 9 isn't.<\/p>\n<p>Let's try to make memory consumption even lower. For example, how about forcing the engine to collect the <code>html<\/code> data when it's no longer needed?<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> urls-2.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  ]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">pageUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">text<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-source\"> html<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">matchAll<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string z-begin\">\/<\/span><span class=\"z-string\">href=&quot;<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">(<\/span><span class=\"z-constant z-other z-character-class z-regexp\">.<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">*<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">?<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">)<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string z-end\">\/<\/span><span class=\"z-keyword\">g<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      linkUrls<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> &lt;---<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=9<\/span><span class=\"z-string\"> urls-2.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- Last few GCs ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">252792:0x5576c8da8bb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     3078 ms: Mark-Compact 8.9 (<\/span><span class=\"z-entity z-name z-function\">12.3<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 7.3 (<\/span><span class=\"z-entity z-name z-function\">12.3<\/span><span class=\"z-source\">) MB, 6.65 \/ 0.02 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.997,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.994<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> scavenge<\/span><span class=\"z-string\"> might<\/span><span class=\"z-string\"> not<\/span><span class=\"z-string\"> succeed<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">252792:0x5576c8da8bb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     3101 ms: Mark-Compact 10.7 (<\/span><span class=\"z-entity z-name z-function\">13.4<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 8.5 (<\/span><span class=\"z-entity z-name z-function\">17.4<\/span><span class=\"z-source\">) MB, 6.27 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.992,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.725<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> scavenge<\/span><span class=\"z-string\"> might<\/span><span class=\"z-string\"> not<\/span><span class=\"z-string\"> succeed<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- JS stacktrace ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">FATAL<\/span><span class=\"z-string\"> ERROR:<\/span><span class=\"z-string\"> Reached<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> limit<\/span><span class=\"z-string\"> Allocation<\/span><span class=\"z-string\"> failed<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> JavaScript<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> out<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> memory<\/span><\/span><\/code><\/pre>\n<p>Nothing's changed! And the reason is actually those very string optimizations we discussed earlier. All the <code>urls<\/code> are actually <code>Sliced<\/code> strings, and that means they all retain references to the whole of <code>html<\/code> data!<\/p>\n<p>The solution is to <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/habr-com.translate.goog\/ru\/articles\/449368\/?_x_tr_sl=ru&amp;_x_tr_tl=en\">scrub those strings clean<\/a>!<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> urls-3.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  ]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">pageUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">text<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-source\"> html<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">matchAll<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string z-begin\">\/<\/span><span class=\"z-string\">href=&quot;<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">(<\/span><span class=\"z-constant z-other z-character-class z-regexp\">.<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">*<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">?<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">)<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string z-end\">\/<\/span><span class=\"z-keyword\">g<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-constant\"> JSON<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">parse<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-constant\">JSON<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">stringify<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> &lt;---<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      linkUrls<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>Looks like black magic alright. But does it work?<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=9<\/span><span class=\"z-string\"> urls-3.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> it works!<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=8<\/span><span class=\"z-string\"> urls-3.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=7<\/span><span class=\"z-string\"> urls-3.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- Last few GCs ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253130:0x5566636cdbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     1621 ms: Scavenge 6.0 (<\/span><span class=\"z-entity z-name z-function\">8.8<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 4.8 (<\/span><span class=\"z-entity z-name z-function\">8.8<\/span><span class=\"z-source\">) MB, 1.45 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 1.000,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 1.000<\/span><span class=\"z-source\">) task<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253130:0x5566636cdbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-entity z-name z-function\">     1631<\/span><span class=\"z-string\"> ms:<\/span><span class=\"z-string\"> Mark-Compact<\/span><span class=\"z-constant z-numeric\"> 4.9<\/span><span class=\"z-source\"> (8.8<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 4.4 (<\/span><span class=\"z-entity z-name z-function\">9.0<\/span><span class=\"z-source\">) MB, 5.01 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.997,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.997<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> GC<\/span><span class=\"z-string\"> in<\/span><span class=\"z-string\"> old<\/span><span class=\"z-string\"> space<\/span><span class=\"z-string\"> requested<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253130:0x5566636cdbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     1642 ms: Mark-Compact 7.3 (<\/span><span class=\"z-entity z-name z-function\">11.8<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 7.0 (<\/span><span class=\"z-entity z-name z-function\">11.8<\/span><span class=\"z-source\">) MB, 1.94 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.996,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.827<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> GC<\/span><span class=\"z-string\"> in<\/span><span class=\"z-string\"> old<\/span><span class=\"z-string\"> space<\/span><span class=\"z-string\"> requested<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- JS stacktrace ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">FATAL<\/span><span class=\"z-string\"> ERROR:<\/span><span class=\"z-string\"> Reached<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> limit<\/span><span class=\"z-string\"> Allocation<\/span><span class=\"z-string\"> failed<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> JavaScript<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> out<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> memory<\/span><\/span><\/code><\/pre>\n<p>As you can see, the code now works fine with a 9 megabyte heap, only OOMing at 7 megabytes. That's two megabytes of RAM reclaimed by forcing the engine to use a specific string implementation.<\/p>\n<p>We can reclaim even more by forcing one-byte representation of all the strings. Even though those string aren't really ASCII, the magic of UTF-8 will ensure our code works like before:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> urls-4.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  ]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">pageUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">arrayBuffer<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> &lt;---<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Buffer<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">from<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">html<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toString<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">ascii<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> &lt;---<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> this regular expression will still work as intended<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> when applied to individual bytes of a UTF-8 string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> instead of proper code points<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-source\"> html<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">matchAll<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string z-begin\">\/<\/span><span class=\"z-string\">href=&quot;<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">(<\/span><span class=\"z-constant z-other z-character-class z-regexp\">.<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">*<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">?<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">)<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string z-end\">\/<\/span><span class=\"z-keyword\">g<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> in case a URL did actually contain non-ASCII chars<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Buffer<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">from<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">ascii<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toString<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">utf-8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      linkUrls<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>With that, we have reclaimed another megabyte:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=7<\/span><span class=\"z-string\"> urls-4.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> it works!<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=6<\/span><span class=\"z-string\"> urls-4.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- Last few GCs ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253789:0x563785444bb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     1749 ms: Mark-Compact 4.9 (<\/span><span class=\"z-entity z-name z-function\">9.3<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 4.4 (<\/span><span class=\"z-entity z-name z-function\">9.5<\/span><span class=\"z-source\">) MB, 2.12 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.996,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.831<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> GC<\/span><span class=\"z-string\"> in<\/span><span class=\"z-string\"> old<\/span><span class=\"z-string\"> space<\/span><span class=\"z-string\"> requested<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253789:0x563785444bb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     2530 ms: Mark-Compact 7.5 (<\/span><span class=\"z-entity z-name z-function\">10.1<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 5.5 (<\/span><span class=\"z-entity z-name z-function\">10.3<\/span><span class=\"z-source\">) MB, 5.66 \/ 0.01 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.994,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.993<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> scavenge<\/span><span class=\"z-string\"> might<\/span><span class=\"z-string\"> not<\/span><span class=\"z-string\"> succeed<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- JS stacktrace ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">FATAL<\/span><span class=\"z-string\"> ERROR:<\/span><span class=\"z-string\"> Reached<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> limit<\/span><span class=\"z-string\"> Allocation<\/span><span class=\"z-string\"> failed<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> JavaScript<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> out<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> memory<\/span><\/span><\/code><\/pre><h2 id=\"in-conclusion\"><a class=\"anchor\" href=\"#in-conclusion\" title=\"link to section\">#<\/a>In conclusion<\/h2>\n<p>Most modern JavaScript engines, including V8, have quite a lot of thought put into optimizing various string operations. In my article, I have explored some of those optimizations. While they might be hard to explicitly make use of, it is still quite useful to remember they exist - if only to debug <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/mrdoob\/three.js\/issues\/9679\">weird and unexpected<\/a> performance problems.<\/p>\n"},{"title":"Explicit Resource Management: Exploring JavaScript's and TypeScript's new feature","published":"2023-11-13T00:00:00+00:00","updated":"2023-11-13T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/js-explicit-resource-management-en\/"}},"id":"https:\/\/iliazeus.lol\/articles\/js-explicit-resource-management-en\/","content":"<p>One of my favorite new features of JavaScript and TypeScript is <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/tc39\/proposal-explicit-resource-management\">explicit resource management<\/a>. It brings new syntax, <code>using foobar = ...<\/code>, that enables <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/en.wikipedia.org\/wiki\/Resource_acquisition_is_initialization\">RAII<\/a>, reducing boilerplate when managing the lifecycle of various resources.<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/js-explicit-resource-management-en\/cover.png\" alt=\"a demo of new syntax\" \/><\/p>\n<p>In this article, I will explore this feature as implemented in <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-2\/#using-declarations-and-explicit-resource-management\">TypeScript 5.2.0<\/a> with the <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/disposablestack\">disposablestack<\/a> polyfill. I will mention both sync and async resources, <code>DisposableStack<\/code>\/<code>AsyncDisposableStack<\/code>, and a non-obvious mistake I've made when using the new feature. Also, along the way, I will use some newer features of Node.js, that some people might not know about yet.<\/p>\n<p>All of the code is available <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/js-disposable-demo\">in the repo<\/a>.<\/p>\n<h2 id=\"prerequisites\"><a class=\"anchor\" href=\"#prerequisites\" title=\"link to section\">#<\/a>Prerequisites<\/h2>\n<p>I will use a more-or-less recent version of Node.js:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-version<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">v20.3.1<\/span><\/span><\/code><\/pre>\n<p>But all of the features I'll use are available at least as of Node 18.16.1 LTS.<\/p>\n<p>I'll need TypeScript 5.2 for the syntax-level, and a polyfill for the library-level part of the feature:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> i<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">D<\/span><span class=\"z-string\"> typescript@5.2<\/span><span class=\"z-string\"> @types\/node@20<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> i<\/span><span class=\"z-string\"> disposablestack<\/span><\/span><\/code><\/pre>\n<p>Finally, to set up the compiler. For this new syntax, I'll need the <code>\"lib\": \"esnext\"<\/code> or <code>\"lib\": \"esnext.disposable\"<\/code> options. I will also use ES modules.<\/p>\n<details>\n<summary>Full tsconfig.json<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> tsconfig.json<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">compilerOptions<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">target<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">es2022<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">lib<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">esnext<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">dom<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">module<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">nodenext<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">rootDir<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/src<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">outDir<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/dist<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">skipLibCheck<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"sync-resources-event-subscriptions\"><a class=\"anchor\" href=\"#sync-resources-event-subscriptions\" title=\"link to section\">#<\/a>Sync resources: event subscriptions<\/h2>\n<p>One of the simpler kinds of resource that a JavaScript or TypeScript programmer might encounter is an event subscription. Its lifecycle begins when subscribing to an event, and ends when unsubscribing from it. And in a lot of cases, forgetting to properly unsubscribe from an event will lead to memory leaks - an event handler is often a closure that retains a reference to the event emitter object, creating a reference cycle:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> listener<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> SomeListener<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> emitter<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> HeavyObject<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">emitter<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">on<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> listener<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">onEvent<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">emitter<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">emitter<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> emitter won&#39;t be garbage collected<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> as long as listener is alive<\/span><\/span><\/code><\/pre>\n<p>Using event subscriptions as an example, let's is what the new resource management syntax looks like. First, to implement the lifecycle logic:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/event-subscription.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">disposablestack\/auto<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> EventEmitter<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:events<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">obj<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> EventEmitter<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> e<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-function\"> fn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-keyword z-operator\">...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Disposable<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">on<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">e<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> fn<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">Symbol<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">dispose<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">off<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">e<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> fn<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>The <code>Disposable<\/code> protocol requires objects to have a <code>[Symbol.dispose]()<\/code> method - this method will be called to free the resource.<\/p>\n<p>To demonstrate this resource's usage, I will write a unit test for <code>subscribe()<\/code> using one of the newer Node.js features - a <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/nodejs.org\/dist\/latest-v20.x\/docs\/api\/test.html\">built-in test runner<\/a>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/event-subscription.test.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> subscribe<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/event-subscription.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-variable z-other z-readwrite\"> assert<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:assert\/strict<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> EventEmitter<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:events<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> describe<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> it<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">describe<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event-subscription<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  it<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">is disposed at scope exit<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> expectedEvents<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 3<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> actualEvents<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> obj<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> EventEmitter<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-entity z-name z-function\"> fn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">e<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> actualEvents<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">e<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> initializing the resource with a `using` declaration<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      using<\/span><span class=\"z-variable z-other z-constant z-js\"> guard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">obj<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> fn<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> the resource is alive till the end of the variable scope<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> e<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> expectedEvents<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\"> obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">emit<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> e<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> end of scope for `guard`<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> guard[Symbol.dispose]() will be called here<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">emit<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 123<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">deepEqual<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">actualEvents<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> expectedEvents<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">listenerCount<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>Let's run our test:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> test<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-function\"> grep<\/span><span class=\"z-string\"> event-subscription<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> Subtest: event-subscription<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">ok<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> event-subscription<\/span><\/span><\/code><\/pre><h2 id=\"async-resources-open-files\"><a class=\"anchor\" href=\"#async-resources-open-files\" title=\"link to section\">#<\/a>Async resources: open files<\/h2>\n<p>When talking about resource lifecycle in Node.js, most people really mean the ones I'll call <em>async resources<\/em>. They include open files, sockets, database connections - in short, any resources that fit the following usage model:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> resource<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Resource<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> the resource is initialized with an async method<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">  resource<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> Resource<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">open<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> doing stuff with resource<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword\"> finally<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> the resource is freed with an async method<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  await<\/span><span class=\"z-source\"> resource<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">close<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>From the first glance, it's not really clear why the new syntax was introduced. I mean, we already have <code>finally<\/code>, right? But as soon as we have to deal with several resource at once, the boilerplate starts to pile up:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> resourceA<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> ResourceA<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">  resourceA<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> ResourceA<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">open<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> resourceB<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> ResourceB<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    resourceB<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> ResourceB<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">open<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">resourceA<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> finally<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    await<\/span><span class=\"z-source\"> resourceB<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">close<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword\"> finally<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  await<\/span><span class=\"z-source\"> resourceA<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">close<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>Adding to that, the <code>try<\/code> and <code>finally<\/code> blocks are different scopes, so we always need to declare mutable variables, instead of using <code>const<\/code>.<\/p>\n<p>The new <code>using<\/code> syntax makes this much more manageable:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/file.test.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> openFile<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/file.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-variable z-other z-readwrite\"> assert<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:assert\/strict<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> describe<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> it<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">describe<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">file<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  it<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">is disposed at scope exit<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      await using<\/span><span class=\"z-variable z-other z-constant z-js\"> file<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">dist\/test.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">w<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      await<\/span><span class=\"z-source\"> file<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writeFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">utf-8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      await using<\/span><span class=\"z-variable z-other z-constant z-js\"> file<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">dist\/test.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">r<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-source\"> file<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">readFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">utf-8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>Notice the <code>await using file = await ...<\/code>. There are two <code>await<\/code>s here. The first <code>await<\/code> means async disposal - that is, executing <code>await file[Symbol.asyncDispose]()<\/code> at the end of scope. The second <code>await<\/code> means async initialization - it is, in fact, just a regular <code>await openFile()<\/code> expression.<\/p>\n<p>I'll implement <code>openFile<\/code> as a thin wrapper over the existing <code>fs.FileHandle<\/code> of Node.js.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/file.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">disposablestack\/auto<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-constant z-language\"> *<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-variable z-other z-readwrite\"> fs<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:fs\/promises<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Writable<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:stream<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> the type of our resource is a union of AsyncDisposable and the fs.FileHandle<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> DisposableFile<\/span><span class=\"z-storage z-modifier\"> extends<\/span><span class=\"z-entity z-name z-type\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-other z-inherited-class\">FileHandle<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-other z-inherited-class\"> AsyncDisposable<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> this helper method will become useful later<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  writableWebStream<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">options<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-type\">CreateWriteStreamOptions<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> WritableStream<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">path<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> flags<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">DisposableFile<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> file<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">open<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">path<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> flags<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> using Object.assign() to monkey-patch the disposal function into the object<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">assign<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">file<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    [<\/span><span class=\"z-source\">Symbol<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">asyncDispose<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> file<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">close<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    writableWebStream<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-type\">CreateWriteStreamOptions<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-source\"> autoClose<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      Writable<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toWeb<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">file<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">createWriteStream<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">options<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>Let's run the tests:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> test<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-function\"> grep<\/span><span class=\"z-string\"> file<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> Subtest: file<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">ok<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> file<\/span><\/span><\/code><\/pre><h2 id=\"the-async-sync-mutexes\"><a class=\"anchor\" href=\"#the-async-sync-mutexes\" title=\"link to section\">#<\/a>The \"async-sync\": mutexes<\/h2>\n<p>From the first glance, the <code>await using foo = await ...<\/code> syntax can seem needlessly repetitive. But the thing is, there are resources that only require the initialization to be async, as well as those that only require async disposal.<\/p>\n<p>As a demonstration of an \"async init - sync dispose\" resource, here is a RAII mutex:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/mutex.test.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Mutex<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/mutex.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-variable z-other z-readwrite\"> assert<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:assert\/strict<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> describe<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> it<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> setTimeout<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-variable z-other z-readwrite\"> sleep<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:timers\/promises<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">describe<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">mutex-guard<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  it<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">is disposed at scope exit<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> mutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Mutex<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> value<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-entity z-name z-function\"> task<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-constant z-numeric\"> 5<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> async init - might have to wait until mutex becomes free<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> sync dispose - just notifying other awaiters<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        using<\/span><span class=\"z-variable z-other z-constant z-js\"> guard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> mutex<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">acquire<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> the scope of `guard` becomes a critical section<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        const<\/span><span class=\"z-variable z-other z-constant z-js\"> newValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> value<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        await<\/span><span class=\"z-entity z-name z-function\"> sleep<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">100<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        value<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> newValue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> comment out the `using guard` line to see a race condition<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    await<\/span><span class=\"z-support z-class\"> Promise<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">all<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-entity z-name z-function\">task<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-function\"> task<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">value<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 10<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>I impmented <code>Mutex<\/code> as an async factory of <code>Disposable<\/code> objects:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/mutex.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">disposablestack\/auto<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> class<\/span><span class=\"z-entity z-name z-type\"> Mutex<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  #promise<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type\"> null<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  async<\/span><span class=\"z-entity z-name z-function\"> acquire<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">Disposable<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    while<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#promise<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#promise<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-entity z-name z-function\"> callback<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#promise<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-support z-class\"> Promise<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">cb<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-variable z-other z-readwrite\"> callback<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> cb<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      [<\/span><span class=\"z-source\">Symbol<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">dispose<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">        this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#promise<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">        callback<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>Let's run the tests:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> test<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-function\"> grep<\/span><span class=\"z-string\"> mutex<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> Subtest: mutex-guard<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">ok<\/span><span class=\"z-constant z-numeric\"> 3<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> mutex-guard<\/span><\/span><\/code><\/pre><h2 id=\"the-sync-async-task-queues\"><a class=\"anchor\" href=\"#the-sync-async-task-queues\" title=\"link to section\">#<\/a>The \"sync-async\": task queues<\/h2>\n<p>As an example of a \"sync init - async dispose\" object, here is a simple task queue:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/task-queue.test.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> TaskQueue<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/task-queue.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-variable z-other z-readwrite\"> assert<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:assert\/strict<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> describe<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> it<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> setTimeout<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-variable z-other z-readwrite\"> sleep<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:timers\/promises<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">describe<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">task-queue<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  it<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">is disposed at scope exit<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> runningTaskCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> maxRunningTaskCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-entity z-name z-function\"> task<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      runningTaskCount<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      maxRunningTaskCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Math<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">max<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">maxRunningTaskCount<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> runningTaskCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      await<\/span><span class=\"z-entity z-name z-function\"> sleep<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">100<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      runningTaskCount<\/span><span class=\"z-keyword z-operator\"> -=<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      await using<\/span><span class=\"z-variable z-other z-constant z-js\"> queue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> TaskQueue<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> concurrency<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      queue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      queue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      queue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      queue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> at the end of scope, it awaits all remaining tasks in the queue<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">runningTaskCount<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">maxRunningTaskCount<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>The implementation is mostly straightforward:<\/p>\n<details>\n<summary>Task queue implementation<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/task-queue.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">disposablestack\/auto<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> EventEmitter<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> once<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:events<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> Task<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> class<\/span><span class=\"z-entity z-name z-type\"> TaskQueue<\/span><span class=\"z-storage z-modifier\"> extends<\/span><span class=\"z-entity z-other z-inherited-class\"> EventEmitter<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0441\u0435\u0439\u0447\u0430\u0441 \u044d\u0442\u043e \u0435\u0449\u0435 \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u043d\u043e \u044d\u0442\u043e \u043f\u043e\u043b\u0435 - \u043e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u0430\u044f \u0434\u0435\u0442\u0430\u043b\u044c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  readonly<\/span><span class=\"z-variable z-object z-property\"> resources<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> AsyncDisposableStack<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  #concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  #tasks<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Task<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  #runningTaskCount<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  constructor<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-object z-property\"> concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-super\">    super<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#concurrency<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> options<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">concurrency<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">on<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">taskFinished<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">#runNextTask<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  push<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">task<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Task<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">#tasks<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">#runNextTask<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  #<\/span><span class=\"z-entity z-name z-function\">runNextTask<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#runningTaskCount<\/span><span class=\"z-keyword z-operator\"> &gt;=<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#concurrency<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> nextTask<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">#tasks<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">shift<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">nextTask<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#runningTaskCount<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    nextTask<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">      .<\/span><span class=\"z-entity z-name z-function\">catch<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">        this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">emit<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">error<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">finally<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">        this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#runningTaskCount<\/span><span class=\"z-keyword z-operator\"> -=<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">        this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">emit<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">taskFinished<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  async<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">Symbol<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">asyncDispose<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    while<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">#tasks<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-keyword z-operator\"> ||<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#runningTaskCount<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      await<\/span><span class=\"z-entity z-name z-function\"> once<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">taskFinished<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">catch<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    await<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">resources<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">disposeAsync<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>Running our simple tests:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> test<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-function\"> grep<\/span><span class=\"z-string\"> queue<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> Subtest: task-queue<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">ok<\/span><span class=\"z-constant z-numeric\"> 4<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> task-queue<\/span><\/span><\/code><\/pre><h2 id=\"putting-it-all-together-fetchcat\"><a class=\"anchor\" href=\"#putting-it-all-together-fetchcat\" title=\"link to section\">#<\/a>Putting it all together: fetchCat()<\/h2>\n<p>As a simple exercise, let's write a function that uses all four of the resources defined earlier:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/fetch-cat.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> subscribe<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/event-subscription.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> openFile<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/file.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Mutex<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/mutex.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> TaskQueue<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/task-queue.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/**<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> * Fetch all `urls` with HTTP GET requests, concatenate all the responses in any order,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> * and write them to `outPath`.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> *<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> * <\/span><span class=\"z-punctuation\">@<\/span><span class=\"z-storage z-type\">param<\/span><span class=\"z-variable z-other z-jsdoc\"> options.concurrency<\/span><span class=\"z-comment\"> max number of concurrent requests<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> * <\/span><span class=\"z-punctuation\">@<\/span><span class=\"z-storage z-type\">param<\/span><span class=\"z-variable z-other z-jsdoc\"> options.onError<\/span><span class=\"z-comment\"> is called on request error<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> *\/<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> fetchCat<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    urls<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    outPath<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    onError<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-constant z-js\"> urls<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> concurrency<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> onError<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> options<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> a task queue to limit the concurrency<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> taskQueue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> TaskQueue<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-other z-readwrite\"> concurrency<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> an event subscription treated as a resource<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  using<\/span><span class=\"z-variable z-other z-constant z-js\"> errorSubscription<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">taskQueue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">error<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> onError<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> synchronize file writes with a mutex<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileMutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Mutex<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ensure the file is closed at the end of scope<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFile<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">w<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> url<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> urls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> a brower-compatible global fetch() is also one]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> of the newer Node.js features<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-variable z-other z-constant z-js\"> response<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">url<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileGuard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> outFileMutex<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">acquire<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> as are the browser-compatible data streams<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        await<\/span><span class=\"z-source\"> response<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">body<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">pipeTo<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">outFile<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writableWebStream<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>Wrapping this up into a script with another Node.js feature - a built-in CLI args parser:<\/p>\n<details>\n<summary>main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/main.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> fetchCat<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/fetch-cat.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> explain<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Error<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> message<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">message<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> e<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cause<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-entity z-name z-type\"> Error<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> e<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> e<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> e<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cause<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-entity z-name z-type\"> Error<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    message<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">: <\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-source\"> e<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">message<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> message<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> args<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  allowPositionals<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    outPath<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">o<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      type<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    concurrency<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">j<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      type<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      default<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">2<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">values<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">outPath<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-string\">missing required option: -o (--outPath)<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">exit<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetchCat<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  urls<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-source\"> args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">positionals<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  outPath<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-source\"> args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">values<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">outPath<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  concurrency<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-entity z-name z-function\"> Number<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">values<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">concurrency<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  onError<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">e<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-entity z-name z-function\">explain<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">e<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<p>To test this, I will use a <code>urls.txt<\/code> file with a list of urls, and a few fakes:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/asdfasdfasdfasdf<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/144758\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/companies\/floor796\/articles\/673318\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/companies\/skyeng\/articles\/487764\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/177159\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/124899\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/149237\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/foobarfoobarfoobar<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/202304\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/307822\/comments\/<\/span><\/span><\/code><\/pre>\n<p>Let's try this out:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> run<\/span><span class=\"z-string\"> demo<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> demo<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> xargs npm run start -- -o .\/cat.html <\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\"> .\/urls.txt<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> start<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> tsc <\/span><span class=\"z-punctuation\">&amp;&amp;<\/span><span class=\"z-entity z-name z-function\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=8<\/span><span class=\"z-string\"> .\/dist\/main-incorrect.js<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">o<\/span><span class=\"z-string\"> .\/cat.html<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-string\"> https:\/\/asdfasdfasdfasdf<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/144758\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/floor796\/articles\/673318\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/skyeng\/articles\/487764\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/177159\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/124899\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/149237\/comments\/<\/span><span class=\"z-string\"> https:\/\/foobarfoobarfoobar<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/202304\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/307822\/comments\/<\/span><\/span><\/code><\/pre>\n<p>Huh... The script won't finish, and the output is empty. Looks like a bug.<\/p>\n<h2 id=\"the-non-obvious-mistake\"><a class=\"anchor\" href=\"#the-non-obvious-mistake\" title=\"link to section\">#<\/a>The non-obvious mistake<\/h2>\n<p>To find my mistake, let's inspect the code a bit closer:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/fetch-cat.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> subscribe<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/event-subscription.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> openFile<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/file.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Mutex<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/mutex.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> TaskQueue<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/task-queue.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> fetchCat<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    urls<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    outPath<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    onError<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-constant z-js\"> urls<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> concurrency<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> onError<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> options<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> notice the resource init order<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> taskQueue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> TaskQueue<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-other z-readwrite\"> concurrency<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  using<\/span><span class=\"z-variable z-other z-constant z-js\"> errorSubscription<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">taskQueue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">error<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> onError<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFile<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">w<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileMutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Mutex<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> url<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> urls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-variable z-other z-constant z-js\"> response<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">url<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileGuard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> outFileMutex<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">acquire<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        await<\/span><span class=\"z-source\"> response<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">body<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">pipeTo<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">outFile<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writableWebStream<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> This is the end of scope for both `outFile` and `taskQueue`.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> They are disposed of in reverse declaration order.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> That means that `outFile` will be closed before `taskQueue` is finished!<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>There is a logic error here: the <code>outFile<\/code> lifetime should be bound not by the current scope, but by the lifetime of all the remaining queue tasks. The file should be closed only when all the tasks are done.<\/p>\n<p>Sadly, Node.js isn't smart enough to automatically prolong the lifetimes of values captured by a closure. That means I'll have to bind them manually, using <code>AsyncDisposableStack<\/code> - a container that aggregates several <code>AsyncDisposable<\/code>s together, freeing them all at once.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/fetch-cat.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> subscribe<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/event-subscription.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> openFile<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/file.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Mutex<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/mutex.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> TaskQueue<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/task-queue.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> fetchCat<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    urls<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    outPath<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    onError<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-constant z-js\"> urls<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> concurrency<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> onError<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> options<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> taskQueue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> TaskQueue<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-other z-readwrite\"> concurrency<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> The `taskQueue.resources` field is an AsyncDisposableStack.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> As part of TaskQueue&#39;s contract, it is disposed only after<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> all the tasks are done<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> errorSubscription<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">taskQueue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">error<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> onError<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">resources<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">use<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">errorSubscription<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> outFile<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">w<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">resources<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">use<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">outFile<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileMutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Mutex<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> url<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> urls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-variable z-other z-constant z-js\"> response<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">url<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileGuard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> outFileMutex<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">acquire<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        await<\/span><span class=\"z-source\"> response<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">body<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">pipeTo<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">outFile<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writableWebStream<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> Only the `taskQueue` resource is bound directly to this scope.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> When it is disposed of, it first awaits all remaining queue tasks,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> and only then disposes of all the `taskQueue.resources`.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> Only then will the `outFile` be closed.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>Let's test this out:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> run<\/span><span class=\"z-string\"> demo<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> demo<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> xargs npm start -- -o .\/cat.html <\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\"> .\/urls.txt<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> start<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> tsc <\/span><span class=\"z-punctuation\">&amp;&amp;<\/span><span class=\"z-entity z-name z-function\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=8<\/span><span class=\"z-string\"> .\/dist\/main.js<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">o<\/span><span class=\"z-string\"> .\/cat.html<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-string\"> https:\/\/asdfasdfasdfasdf<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/144758\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/floor796\/articles\/673318\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/skyeng\/articles\/487764\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/177159\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/124899\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/149237\/comments\/<\/span><span class=\"z-string\"> https:\/\/foobarfoobarfoobar<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/202304\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/307822\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">fetch<\/span><span class=\"z-string\"> failed:<\/span><span class=\"z-string\"> getaddrinfo<\/span><span class=\"z-string\"> ENOTFOUND<\/span><span class=\"z-string\"> asdfasdfasdfasdf<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">fetch<\/span><span class=\"z-string\"> failed:<\/span><span class=\"z-string\"> getaddrinfo<\/span><span class=\"z-string\"> ENOTFOUND<\/span><span class=\"z-string\"> foobarfoobarfoobar<\/span><\/span><\/code><\/pre>\n<p>Excellent! All the urls (excluding fakes) were fetched and written to <code>.\/cat.html<\/code>, as intended.<\/p>\n<p>As a general rule, all <code>Disposable<\/code> resources that hold sub-resources should hold them in a <code>DisposableStask<\/code>, disposing it inside their own <code>dispose()<\/code>. Same goes for <code>AsyncDisposable<\/code> and <code>AsyncDisposableStask<\/code>, of course.<\/p>\n<h2 id=\"article-symbol-dispose\"><a class=\"anchor\" href=\"#article-symbol-dispose\" title=\"link to section\">#<\/a><code>article[Symbol.dispose]()<\/code><\/h2>\n<p>The dedicated RAII syntax isn't a novel idea for a programming language - <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/proposals\/csharp-8.0\/using#using-declaration\">C# has it<\/a>, so <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.python.org\/3\/reference\/compound_stmts.html#the-with-statement\">does Python<\/a>, and now JavaScript and TypeScript. This implementation, of course, isn't perfect, and has its own share of non-obvious behaviors. But still, I am glad that we finally have such a syntax - and, I hope, I managed to explain why!<\/p>\n<p>All the code is available <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/js-disposable-demo\">in the repo<\/a>.<\/p>\n"},{"title":"\u041a\u0430\u043a \u044f \u043f\u0438\u0441\u0430\u043b \u043f\u043e\u0434 \u0424\u043b\u0438\u043f\u043f\u0435\u0440 \u043d\u0430 \u0421\u0438-\u0441-\u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438","published":"2023-10-19T00:00:00+00:00","updated":"2023-10-19T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/flipper-c-with-classes-ru\/"}},"id":"https:\/\/iliazeus.lol\/articles\/flipper-c-with-classes-ru\/","content":"<p>\u041c\u043e\u0439 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/flipperzero.one\/\">\u0424\u043b\u0438\u043f\u043f\u0435\u0440<\/a> \u0434\u043e\u0448\u0435\u043b \u0434\u043e \u043c\u0435\u043d\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u043b\u0443\u0433\u043e\u0434\u0430 \u043d\u0430\u0437\u0430\u0434, \u043d\u043e \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0434 \u043d\u0435\u0433\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u044f \u0441\u043e\u0431\u0440\u0430\u043b\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0439\u0447\u0430\u0441. \u0415\u0433\u043e API \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u044b \u043d\u0430 \u044f\u0437\u044b\u043a \u0421 \u2014 \u0430 \u0443 \u043c\u0435\u043d\u044f \u0441 \u043d\u0438\u043c \u043e\u043f\u044b\u0442\u0430 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e. \u041d\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u0442\u0443\u043b\u0438\u043d\u0433\u043e\u043c \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u043e \u2014 \u0443 \u0424\u043b\u0438\u043f\u043f\u0435\u0440\u0430 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u044f <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/flipperdevices\/flipperzero-firmware\/blob\/dev\/documentation\/fbt.md\">\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u0431\u043e\u0440\u043a\u0438<\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043a\u0430\u0447\u0430\u043b\u0430 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u044b\u0439 \u0442\u0443\u043b\u0447\u0435\u0439\u043d \u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f IDE.<\/p>\n<p>\u0410 \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u044f \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0436\u0435 \u043d\u0435 C, \u0430 C++ \u2014 \u0442\u043e\u0447\u043d\u0435\u0435, \u0434\u0430\u0436\u0435 \"\u0421\u0438-\u0441-\u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438\". \u041d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0437\u0430\u0442\u0443\u043c\u0430\u043d\u0435\u043d\u043d\u044b\u0439 \u044f\u0437\u044b\u043a\u0430\u043c\u0438 \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f, \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0443\u0434\u043e\u0431\u043d\u0435\u0435, \u0447\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430 \u0447\u0438\u0441\u0442\u043e\u043c C. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/furi-cpp\">\u0432 \u043c\u043e\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>, \u0430 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u043f\u044b\u0442\u0430\u044e\u0441\u044c \u043e\u043f\u0438\u0441\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0444\u0438\u0447\u0438 \u044f\u0437\u044b\u043a\u0430 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b, \u0438 \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d\u0438 \u043c\u043d\u0435 \u043f\u043e\u043c\u043e\u0433\u043b\u0438.<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/flipper-c-with-classes-ru\/cover.png\" alt=\"\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c\" \/><\/p>\n<p>\u0421\u0440\u0430\u0437\u0443 \u0441\u043a\u0430\u0436\u0443, \u0447\u0442\u043e \u043c\u043e\u0435\u0439 \u0446\u0435\u043b\u044c\u044e \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0445 C++-\u0431\u0438\u043d\u0434\u0438\u043d\u0433\u043e\u0432 \u0434\u043b\u044f API \u0444\u043b\u0438\u043f\u043f\u0435\u0440\u0430. \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435, \u043e\u0431\u0435\u0440\u043d\u0443\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0437\u0434\u0435\u0448\u043d\u0435\u0433\u043e API \u0432 \u043a\u043b\u0430\u0441\u0441\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0438 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0432\u043c\u0435\u0441\u0442\u043e <code>_alloc()<\/code>- \u0438 <code>_free()<\/code>-\u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0432 \u0441\u043e\u0432\u0441\u0435\u043c, \u044f \u0441\u043c\u043e\u0433 \u0431\u044b \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u0435\u0435 \u0438\u0434\u0438\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e C++. \u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e \u0431\u044b \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0437\u0430\u0442\u0440\u0430\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435, \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e, \u044f \u0438\u0441\u043a\u0430\u043b \u043e\u0442 C++ \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u0441\u0430\u043c\u044b\u0445 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043d\u0435\u0443\u0434\u043e\u0431\u0441\u0442\u0432 \u2014 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438 \u0445\u043e\u0447\u0443 \u0441 \u0432\u0430\u043c\u0438 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f.<\/p>\n<h2 id=\"prostranstva-imen\"><a class=\"anchor\" href=\"#prostranstva-imen\" title=\"link to section\">#<\/a>\u041f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0438\u043c\u0435\u043d<\/h2>\n<p>\u0412 \u0441\u0438\u0448\u043d\u044b\u0445 API \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441 \u0434\u043b\u0438\u043d\u043d\u044b\u043c\u0438 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430\u043c\u0438: <code>mylib_mything_get_foo()<\/code>, <code>MylibMyenumFirst<\/code>. \u041f\u043e\u0440\u043e\u0439 \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043a\u043e\u0434 \u0447\u0440\u0435\u0437\u0432\u044b\u0447\u0430\u0439\u043d\u043e \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u043c \u2014 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0432 \u0442\u0435\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445, \u043a\u043e\u0433\u0434\u0430 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u043f\u043e\u043b\u043d\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e <code>get_foo()<\/code> \u043c\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043b\u044f <code>mything<\/code> \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>mylib<\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u044f \u0445\u043e\u0442\u0435\u043b \u0440\u0430\u0441\u043a\u0438\u0434\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u0430 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430\u043c \u0438\u043c\u0435\u043d.<\/p>\n<p>\u0414\u043b\u044f \u0442\u0438\u043f\u043e\u0432 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0442\u0438\u043f\u044b-\u0430\u043b\u0430\u0441\u044b. \u0412\u0440\u043e\u0434\u0435 \u0442\u0430\u043a\u0438\u0445:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">namespace<\/span><span class=\"z-entity z-name z-namespace\"> furi<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  using<\/span><span class=\"z-entity z-name z-type\"> Timer<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> ::<\/span><span class=\"z-entity z-name z-type\">FuriTimer<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  using<\/span><span class=\"z-entity z-name z-type\"> Mutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> ::<\/span><span class=\"z-entity z-name z-type\">FuriMutex<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0414\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0432\u0441\u0435 \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">namespace<\/span><span class=\"z-source\"> furi<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-namespace\">mutex<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  constexpr<\/span><span class=\"z-storage z-modifier\"> inline<\/span><span class=\"z-storage z-type\"> auto<\/span><span class=\"z-keyword z-operator\">&amp;<\/span><span class=\"z-source\"> acquire <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::furi_mutex_acquire<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u041f\u043e\u0434\u0445\u043e\u0434 \u0441 \u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438 \u0438\u043c\u0435\u0435\u0442 \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u044e\u0441\u043e\u0432. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, <code>constexpr<\/code>-\u0441\u0441\u044b\u043b\u043a\u0438 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u0438\u043d\u043b\u0430\u0439\u043d\u044f\u0442\u0441\u044f, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044f\u0441\u044c \u043f\u0440\u043e\u0441\u0442\u043e \u0432 \u0432\u044b\u0437\u043e\u0432\u044b \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u043e\u0432 \u2014 \u0432 \u043c\u043e\u0438\u0445 \u0442\u0435\u0441\u0442\u0430\u0445 \u0443 \u043c\u0435\u043d\u044f \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0435-\u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u044d\u0442\u043e - \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043e\u0431\u0435\u0440\u0442\u043e\u043a \u2014 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u043c\u043e\u044f IDE \u0434\u0430\u0436\u0435 \u043f\u043e\u0434\u0442\u044f\u043d\u0443\u043b\u0430 \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0441\u0441\u044b\u043b\u043e\u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u043e\u0432:<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/flipper-c-with-classes-ru\/function-reference-docs.png\" alt=\"\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0432\u043e \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0435\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0435 IDE\" \/><\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0440\u043e\u0447\u043a\u0435 <code>constexpr inline auto&amp;<\/code>, \u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0430\u043a\u0440\u043e\u0441 <code>FURI_HH_ALIAS<\/code>. \u0414\u043b\u044f \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432 \u0432 C++, \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432 \u0438\u043c\u0435\u043d \u043d\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0433\u043e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c.<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e <code>enum<\/code>\u044b. \u0418\u0434\u0438\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u043c C++ \u0431\u044b\u043b\u043e \u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043d\u0438\u0445 <code>enum class<\/code> \u2014 \u043d\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0443\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u0442\u0438\u043f\u044b, \u0438 \u043e\u0434\u0438\u043d \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0430\u043c\u0438 \u043f\u043e \u0441\u0435\u0431\u0435 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0443\u0442. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f \u043d\u0430 \u0430\u043b\u0438\u0430\u0441\u0430\u0445 \u0438 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430\u0445 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c <code>namespace<\/code>, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0432\u0441\u0435 \u0442\u043e\u0442 \u0436\u0435 \u043c\u0430\u043a\u0440\u043e\u0441 <code>FURI_HH_ALIAS<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">namespace<\/span><span class=\"z-source\"> furi<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-namespace\">mutex<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  using<\/span><span class=\"z-entity z-name z-type\"> Type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> ::<\/span><span class=\"z-entity z-name z-type\">FuriMutexType<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  namespace<\/span><span class=\"z-entity z-name z-namespace\"> type<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    FURI_HH_ALIAS Normal <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::FuriMutexTypeNormal<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    FURI_HH_ALIAS Recursive <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::FuriMutexTypeRecursive<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435, \u043c\u043e\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0441\u0442\u0430\u043b\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u0430\u043a-\u0442\u043e \u0442\u0430\u043a:<\/p>\n<details>\n<summary>mutex.hh<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">pragma<\/span><span class=\"z-entity z-other z-attribute-name\"> once<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">include<\/span><span class=\"z-punctuation z-definition z-string\"> &lt;<\/span><span class=\"z-string\">furi.h<\/span><span class=\"z-punctuation z-definition z-string\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">include<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">furi\/macros.hh<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">include<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">furi\/own.hh<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">namespace<\/span><span class=\"z-entity z-name z-namespace\"> furi<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  using<\/span><span class=\"z-entity z-name z-type\"> Mutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> ::<\/span><span class=\"z-entity z-name z-type\">FuriMutex<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  using<\/span><span class=\"z-entity z-name z-type\"> MutexOwn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Own<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-type\">FuriMutex<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> ::<\/span><span class=\"z-entity z-name z-type\">furi_mutex_free<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  namespace<\/span><span class=\"z-entity z-name z-namespace\"> mutex<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    using<\/span><span class=\"z-entity z-name z-type\"> Type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> ::<\/span><span class=\"z-entity z-name z-type\">FuriMutexType<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    namespace<\/span><span class=\"z-entity z-name z-namespace\"> type<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      FURI_HH_ALIAS Normal <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::FuriMutexTypeNormal<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      FURI_HH_ALIAS Recursive <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::FuriMutexTypeRecursive<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    FURI_HH_ALIAS alloc <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::furi_mutex_alloc<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    FURI_HH_ALIAS free <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::furi_mutex_free<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    FURI_HH_ALIAS acquire <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::furi_mutex_acquire<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    FURI_HH_ALIAS release <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::furi_mutex_release<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    FURI_HH_ALIAS get_owner <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> ::furi_mutex_get_owner<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"vladeiushchie-ukazateli\"><a class=\"anchor\" href=\"#vladeiushchie-ukazateli\" title=\"link to section\">#<\/a>\u0412\u043b\u0430\u0434\u0435\u044e\u0449\u0438\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438<\/h2>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u043d\u0435\u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e, \u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u2014 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441\u044b. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043f\u0440\u0438\u0432\u044b\u043a \u043a \u044f\u0437\u044b\u043a\u0430\u043c, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0435\u0441\u0442\u044c <code>using<\/code>, \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0438\u043b\u0438 \u0445\u043e\u0442\u044f \u0431\u044b <code>try-finally<\/code>, \u043d\u043e \u043c\u043d\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u044d\u0442\u0438\u043c \u0441\u0430\u043c\u043e\u043c\u0443. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0440\u0430\u043d\u043d\u0438\u0445 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043e\u0432 \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0432\u043b\u0430\u0434\u0435\u043d\u0438\u044f \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u043c.<\/p>\n<p>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \"\u0432\u043b\u0430\u0434\u0435\u044e\u0449\u0438\u0439\" \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u0432 C++ \u2014 \u044d\u0442\u043e <code>std::unique_ptr<\/code>. \u041d\u043e \u043e\u043d \u043c\u043d\u0435 \u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u0435\u043b \u043f\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c.<\/p>\n<p>\u041f\u0435\u0440\u0432\u0430\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0437\u0430\u0438\u0447\u043d\u0430: <code>std::unique_ptr&lt;T&gt;<\/code> \u043d\u0435 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432 <code>T*<\/code>, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>.get()<\/code>. \u0412 API \u0424\u043b\u0438\u043f\u043f\u0435\u0440\u0430 \u0432\u043b\u0430\u0434\u0435\u043d\u0438\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u043c, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u2014 \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u044f <code>_free()<\/code>-\u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u043d\u0435\u0447\u043d\u043e. \u0410 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u0435\u0437\u0434\u0435 <code>.get()<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0432\u043d\u043e.<\/p>\n<p>\u0414\u0440\u0443\u0433\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u0435\u0435, \u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u0430 \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u044b API \u0424\u043b\u0438\u043f\u043f\u0435\u0440\u0430 \u0438 \u043b\u043e\u0433\u0438\u043a\u0430.<\/p>\n<p>\u0423 <code>std::unique_ptr<\/code> \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0442\u043e\u0440\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442 <code>Deleter<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/en.cppreference.com\/w\/cpp\/memory\/unique_ptr\/get_deleter\">\u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c<\/a> \u0437\u0430 \u0442\u043e, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c. \u041b\u043e\u0433\u0438\u043a\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f: \u0434\u043b\u044f \u0442\u0438\u043f\u0430 <code>T<\/code> \u0443 \u043d\u0435\u0433\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c <code>operator()(T*)<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044d\u0442\u043e\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u0442.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0445\u043e\u0442\u0435\u043b \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>Deleter<\/code>, \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0435\u0435 <code>operator()<\/code> \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u0442\u0438\u043f\u043e\u0432 \u0432 API:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-modifier\">inline<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-source\"> Deleter<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">Mutex<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword\">operator<\/span><span class=\"z-source\">()<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">Mutex<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> m<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  ::<\/span><span class=\"z-entity z-name z-function\">furi_mutex_free<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">m<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u041d\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u0430\u0441\u044c \u043e\u0447\u0435\u043d\u044c \u043e\u0431\u0438\u0434\u043d\u0430\u044f \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c API \u0424\u043b\u0438\u043f\u043f\u0435\u0440\u0430.<\/p>\n<p>\u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043a\u043e\u0433\u0434\u0430 \u0432 \u0441\u0438\u0448\u043d\u044b\u0445 API \u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u044e\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438, \u043e\u043d\u0438 \u0447\u0430\u0441\u0442\u043e \"\u043d\u0435\u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u044b\u0435\" \u2014 \u043d\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u044b\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c, \u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441 \u044d\u0442\u0438\u043c \u0436\u0435 \u0441\u0430\u043c\u044b\u043c API. \u041e\u043d\u0438 \u043e\u0431\u044b\u0447\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u0430\u043a:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0431\u0435\u0437 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">typedef<\/span><span class=\"z-storage z-type\"> struct<\/span><span class=\"z-source\"> MyStruct<\/span><span class=\"z-entity z-name z-type\"> MyStruct<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-type\">MyStruct<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-entity z-name z-function\"> mystruct_alloc<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u041d\u043e \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u0445 \u0424\u043b\u0438\u043f\u043f\u0435\u0440\u0430 \u0447\u0430\u0441\u0442\u043e \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u0442\u0441\u044f \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0435:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> furi\/core\/mutex.h<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">typedef<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-source\"> FuriMutex<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> furi\/core\/timer.h<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">typedef<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-source\"> FuriTimer<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> furi\/code\/message_queue.h<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">typedef<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-source\"> FuriMessageQueue<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u041f\u043e\u0434\u0432\u043e\u0445 \u0432 \u044d\u0442\u043e\u043c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0442\u0438\u043f\u043e\u0432 \u0432\u0441\u0435 \u044d\u0442\u0438 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u2014 \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u0442\u0438\u043f! \u0410 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043f\u043e \u043d\u0438\u043c \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u043a\u0438, \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0437\u044f\u0442\u044c \u0438 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 <code>Deleter::operator()<\/code> \u0434\u043b\u044f \u043d\u0438\u0445 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f.<\/p>\n<p>\u041f\u043e\u043b\u044c\u0437\u0443\u044f\u0441\u044c \u0441\u043b\u0443\u0447\u0430\u0435\u043c: \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u0447\u0438\u0442\u0430\u044e\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0424\u043b\u0438\u043f\u043f\u0435\u0440\u0430 \u2014 pls fix.<\/p>\n<p>\u0410 \u044f, \u0432 \u0438\u0442\u043e\u0433\u0435, \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u043d\u0430\u0434 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c <code>std::unique_ptr<\/code>. \u0412\u043e\u0442 \u0442\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u043b\u0430\u0434\u0435\u044e\u0449\u0438\u0445 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">namespace<\/span><span class=\"z-entity z-name z-namespace\"> furi<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  using<\/span><span class=\"z-entity z-name z-type\"> MutexOwn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Own<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-type\">FuriMutex<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> ::<\/span><span class=\"z-entity z-name z-type\">furi_mutex_free<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  using<\/span><span class=\"z-entity z-name z-type\"> TimerOwn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Own<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-type\">FuriTimer<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> ::<\/span><span class=\"z-entity z-name z-type\">furi_timer_free<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  using<\/span><span class=\"z-entity z-name z-type\"> MessageQueueOwn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Own<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-type\">FuriMessageQueue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> ::<\/span><span class=\"z-entity z-name z-type\">furi_message_queue_free<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0412\u043e\u0442 \u0442\u0430\u043a \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  using<\/span><span class=\"z-storage z-type\"> namespace<\/span><span class=\"z-entity z-name z-namespace\"> furi<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  MutexOwn m <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-entity z-name z-scope-resolution z-cpp\"> mutex<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-function\">alloc<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  auto<\/span><span class=\"z-source\"> thread_id <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-entity z-name z-scope-resolution z-cpp\"> mutex<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-function\">get_owner<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">m<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u2014 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043d\u043e \u0435\u0441\u043b\u0438 \u043e\u0447\u0435\u043d\u044c \u043d\u0443\u0436\u043d\u043e, \u0432\u0441\u0435 \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0440\u0443\u043a\u0430\u043c\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">  mutex<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-function\">free<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-function\">move<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">m<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0410 \u0432\u043e\u0442 \u0442\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/p>\n<details>\n<summary>own.hh<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">pragma<\/span><span class=\"z-entity z-other z-attribute-name\"> once<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">include<\/span><span class=\"z-punctuation z-definition z-string\"> &lt;<\/span><span class=\"z-string\">memory<\/span><span class=\"z-punctuation z-definition z-string\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">namespace<\/span><span class=\"z-entity z-name z-namespace\"> furi<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  namespace<\/span><span class=\"z-entity z-name z-namespace\"> own<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    template<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> T<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-keyword\"> using<\/span><span class=\"z-entity z-name z-type\"> Free<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-keyword z-operator\">&amp;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">T<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  template<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> T<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> own<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">Free<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-entity z-name z-type\">T<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-storage z-type\"> F<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-storage z-type\"> class<\/span><span class=\"z-entity z-name z-type\"> Own<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    struct<\/span><span class=\"z-entity z-name z-type\"> _Destroy<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      void<\/span><span class=\"z-keyword\"> operator<\/span><span class=\"z-source\">()<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">T<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-entity z-name z-function\"> F<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation\"> }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">    std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">unique_ptr<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">T<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> _Destroy<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> _ptr<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  public<\/span><span class=\"z-punctuation\">:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    Own<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-entity z-name z-function\"> _ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-constant z-language\">nullptr<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> _Destroy{}<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    Own<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">T<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-entity z-name z-function\"> _ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">ptr<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> _Destroy{}<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    Own<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-modifier\">const<\/span><span class=\"z-entity z-name z-type\"> Own<\/span><span class=\"z-storage z-modifier z-reference z-cpp\">&amp;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> delete<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    Own<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">Own<\/span><span class=\"z-storage z-modifier z-reference z-cpp\">&amp;<\/span><span class=\"z-storage z-modifier z-reference z-cpp\">&amp;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> default<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-type\">    Own<\/span><span class=\"z-storage z-modifier z-reference z-cpp\">&amp;<\/span><span class=\"z-keyword\"> operator<\/span><span class=\"z-source\">=<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-modifier\">const<\/span><span class=\"z-entity z-name z-type\"> Own<\/span><span class=\"z-storage z-modifier z-reference z-cpp\">&amp;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> delete<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-type\">    Own<\/span><span class=\"z-storage z-modifier z-reference z-cpp\">&amp;<\/span><span class=\"z-keyword\"> operator<\/span><span class=\"z-source\">=<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">Own<\/span><span class=\"z-storage z-modifier z-reference z-cpp\">&amp;<\/span><span class=\"z-storage z-modifier z-reference z-cpp\">&amp;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> default<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    operator<\/span><span class=\"z-source\"> T<\/span><span class=\"z-source\">*<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-keyword\"> return<\/span><span class=\"z-source\"> _ptr<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">get<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation\"> }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    operator<\/span><span class=\"z-storage z-modifier\"> const<\/span><span class=\"z-source\"> T<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-modifier\"> const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-keyword\"> return<\/span><span class=\"z-source\"> _ptr<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">get<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation\"> }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-type\">    T<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-entity z-name z-function\"> get_mut<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-modifier\"> const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-keyword\"> return<\/span><span class=\"z-source\"> _ptr<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">get<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation\"> }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"defer\"><a class=\"anchor\" href=\"#defer\" title=\"link to section\">#<\/a>defer<\/h2>\n<p>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a RAII \u044f \u0447\u0443\u0432\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f-\u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u0430\u043c\u044f\u0442\u0438, \u043d\u043e \u0438 \u043c\u043d\u043e\u0433\u0438\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043c\u044c\u044e\u0442\u0435\u043a\u0441\u043e\u0432. \u0418\u043b\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f <code>ViewPort<\/code> \u0438\u0437 GUI \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u0437\u043e\u0432\u043e\u043c <code>view_port_free()<\/code> \u2014 \u044d\u0442\u043e\u0442 \u0431\u0430\u0433 \u044f \u0438\u0441\u043a\u0430\u043b \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0433\u043e. \u041f\u0438\u0441\u0430\u0442\u044c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f \u0441\u0432\u043e\u0439 guard-\u043a\u043b\u0430\u0441\u0441 \u043c\u043d\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0438\u0434\u0435\u044e \u0438\u0437 \u0434\u0440\u0443\u0433\u0438\u0445 \u044f\u0437\u044b\u043a\u043e\u0432 \u2014 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b <code>defer<\/code>.<\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">  mutex<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-function\">acquire<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">m<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  defer<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-source\">mutex<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-function\">release<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">m<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0437\u0434\u0435\u0441\u044c \u043c\u044c\u044e\u0442\u0435\u043a\u0441 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">  gui<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-function\">add_view_port<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">gui<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> vp<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  defer<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-source\">gui<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-function\">remove_view_port<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">gui<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> vp<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0437\u0434\u0435\u0441\u044c ViewPort \u0443\u0434\u0430\u043b\u0435\u043d<\/span><\/span><\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0438\u0447\u0435\u043c \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u0430 \u2014 \u0438\u0434\u0435\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u0442\u0430\u0440\u0430:<\/p>\n<details>\n<summary>defer.hh<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">pragma<\/span><span class=\"z-entity z-other z-attribute-name\"> once<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">include<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">furi\/macros.hh<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">namespace<\/span><span class=\"z-entity z-name z-namespace\"> furi<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  template<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> F<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-storage z-type\"> class<\/span><span class=\"z-entity z-name z-type\"> Defer<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    F _fn<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  public<\/span><span class=\"z-punctuation\">:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    Defer<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">F<\/span><span class=\"z-storage z-modifier z-reference z-cpp\"> &amp;<\/span><span class=\"z-storage z-modifier z-reference z-cpp\">&amp;<\/span><span class=\"z-variable z-parameter\">fn<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-entity z-name z-function\"> _fn<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">fn<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    ~Defer<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-entity z-name z-function\"> _fn<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation\"> }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">  #<\/span><span class=\"z-keyword z-control z-directive\">define<\/span><span class=\"z-entity z-name z-function\"> FURI_HH_CONCAT_IMPL<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">x<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\">y<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-source\"> x<\/span><span class=\"z-source\">##y<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">  #<\/span><span class=\"z-keyword z-control z-directive\">define<\/span><span class=\"z-entity z-name z-function\"> FURI_HH_CONCAT<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">x<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\">y<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-entity z-name z-function\"> FURI_HH_CONCAT_IMPL<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">x<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\">y<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">  #<\/span><span class=\"z-keyword z-control z-directive\">define<\/span><span class=\"z-entity z-name z-function\"> defer<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">code<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> auto<\/span><span class=\"z-entity z-name z-function\"> FURI_HH_CONCAT<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">_defer_<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> __COUNTER__<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Defer<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-punctuation\">[<\/span><span class=\"z-keyword z-operator\">&amp;<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> code<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"kolbeki\"><a class=\"anchor\" href=\"#kolbeki\" title=\"link to section\">#<\/a>\u041a\u043e\u043b\u0431\u0435\u043a\u0438<\/h2>\n<p>\u0412 API \u0424\u043b\u0438\u043f\u043f\u0435\u0440\u0430 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442 \u043a\u043e\u043b\u0431\u0435\u043a\u0438 \u2014 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0442\u044c \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445, \u0438\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043a\u043e\u0434 \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435. \u041e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0434\u043b\u044f \u0441\u0438\u0448\u043d\u044b\u0445 API:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u043a\u043e\u043b\u0431\u0435\u043a, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0435\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">void<\/span><span class=\"z-entity z-name z-function\"> furi_timer_pending_callback<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">FuriTimerPendigCallback<\/span><span class=\"z-variable z-parameter\"> callback<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> context<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-type\"> uint32_t<\/span><span class=\"z-variable z-parameter\"> arg<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043a\u043e\u0433\u0434\u0430 \u043a\u043e\u043b\u0431\u0435\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d, \u044d\u0442\u043e\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0435\u043c\u0443 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">typedef<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">*<\/span><span class=\"z-source\">FuriTimerPendigCallback<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-type\">void<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> context<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-type\"> uint32_t<\/span><span class=\"z-variable z-parameter\"> arg<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u041d\u0435\u0443\u0434\u043e\u0431\u0441\u0442\u0432 \u0432 \u0442\u0430\u043a\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u0434\u0432\u0430.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043a\u043e\u043b\u0431\u0435\u043a\u0438 \u0431\u044b\u0432\u0430\u0435\u0442 \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u043b\u0435\u043a\u043e \u043e\u0442 \u043c\u0435\u0441\u0442\u0430 \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f. \u0414\u043b\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043a\u043e\u043b\u0431\u0435\u043a\u043e\u0432 \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">void<\/span><span class=\"z-entity z-name z-function\"> my_callback<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-type\">void<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> ctx<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\">...<\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><span class=\"z-punctuation\"> }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">void<\/span><span class=\"z-entity z-name z-function\"> my_long_function<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  mylib_use_callback<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">ctx<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> my_callback<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0412\u0435\u0440\u043d\u0435\u0435, \u043e\u0437\u043d\u0430\u0447\u0430\u043b\u043e \u0432 C \u2014 \u0430 \u0432 C++ \u0435\u0441\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/stackoverflow.com\/a\/18889029\/7214622\">\"\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435\" \u043b\u044f\u043c\u0431\u0434\u044b<\/a>! \u041e\u043d\u0438 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043d\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044e.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">void<\/span><span class=\"z-entity z-name z-function\"> my_long_function<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  mylib_use_callback<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">ctx<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-punctuation\">[<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-type\">void<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> ctx<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\">...<\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> ...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0412\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441\u0432\u044f\u0437\u0430\u043d\u0430 \u0441 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u0435\u0439. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0432 \u0441\u0438\u0448\u043d\u043e\u043c API \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043e\u0431\u043e\u0431\u0449\u0435\u043d\u043d\u043e\u0439 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u043a\u043e\u043b\u0431\u0435\u043a\u0430 \u2014 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0441 \u043d\u0438\u043c \u043a\u0430\u043a \u0441 <code>void*<\/code>. \u041d\u043e \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u0430\u0441\u0442\u043e\u0432, \u0438 \u043a \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u0441\u043a\u0430\u0441\u0442\u0438\u0442\u044c \u043d\u0435 \u0432 \u0442\u043e\u0442 \u0442\u0438\u043f.<\/p>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u0438\u043f\u043e\u0432 <code>FuriMutex<\/code> \u0438 <code>FuriTimer<\/code>, \u043a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0435\u043b\u0438 \u0432\u044b\u0448\u0435, \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0434\u0430\u0436\u0435 \u043d\u0435 \u0440\u0443\u0433\u043d\u0435\u0442\u0441\u044f.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443-\u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0434\u043b\u044f \u043f\u0430\u0440\u044b \"\u043a\u043e\u043b\u0431\u0435\u043a-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\"... \u043d\u043e \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0435\u0449\u0435 \u043e\u0434\u043d\u043e \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u0430\u0447\u043d\u043e\u0435 \u2014 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f C++ \u2014 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432 API \u0424\u043b\u0438\u043f\u043f\u0435\u0440\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0433\u0434\u0435-\u0442\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c...<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">typedef<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">*<\/span><span class=\"z-source\">FuriTimerPendigCallback<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-type\">void<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> context<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-type\"> uint32_t<\/span><span class=\"z-variable z-parameter\"> arg<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> ...\u0430 \u0433\u0434\u0435-\u0442\u043e \u2014 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c!<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">typedef<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">*<\/span><span class=\"z-source\">ViewPortDrawCallback<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">Canvas<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> canvas<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> context<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u042f \u043e\u0447\u0435\u043d\u044c \u0434\u043e\u043b\u0433\u043e \u043b\u043e\u043c\u0430\u043b \u0433\u043e\u043b\u043e\u0432\u0443 \u043d\u0430\u0434 \u0442\u0435\u043c, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u043d\u0430 \u043e\u0431\u0430 \u0441\u043b\u0443\u0447\u0430\u044f, \u043d\u043e \u043f\u043e\u0442\u043e\u043c \u043f\u043b\u044e\u043d\u0443\u043b \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u0432\u0435:<\/p>\n<details>\n<summary>callback.hh<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">pragma<\/span><span class=\"z-entity z-other z-attribute-name\"> once<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">namespace<\/span><span class=\"z-entity z-name z-namespace\"> furi<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  namespace<\/span><span class=\"z-entity z-name z-namespace\"> cb<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    template<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-storage z-type\">class<\/span><span class=\"z-punctuation\">...<\/span><span class=\"z-entity z-name z-type\"> As<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-keyword\"> using<\/span><span class=\"z-entity z-name z-type\"> FnPtr<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">As...<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0437\u0434\u0435\u0441\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u2014 \u043f\u0435\u0440\u0432\u044b\u0439 \u0430\u0433\u0440\u0443\u043c\u0435\u043d\u0442<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  template<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-storage z-type\">class<\/span><span class=\"z-punctuation\">...<\/span><span class=\"z-entity z-name z-type\"> As<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-storage z-type\"> struct<\/span><span class=\"z-entity z-name z-type\"> Cb<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    using<\/span><span class=\"z-entity z-name z-type\"> FnPtr<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-scope-resolution z-cpp\"> cb<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-type\">FnPtr<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-storage z-type\">void<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> As...<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    void<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-source\"> ctx<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    FnPtr fn_ptr<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    Cb<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-entity z-name z-function\"> ctx<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-constant z-language\">nullptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-function\"> fn_ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-constant z-language\">nullptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    Cb<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">FnPtr<\/span><span class=\"z-variable z-parameter\"> fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-entity z-name z-function\"> ctx<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-constant z-language\">nullptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-function\"> fn_ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    template<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> C<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-entity z-name z-function\"> Cb<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">C<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-source\"> ctx<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-scope-resolution z-cpp\"> cb<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">FnPtr<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">C<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> As...<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      :<\/span><span class=\"z-entity z-name z-function\"> ctx<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-keyword z-operator\">static_cast<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-storage z-type\">void<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">ctx<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      ,<\/span><span class=\"z-entity z-name z-function\"> fn_ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-keyword z-operator\">reinterpret_cast<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">FnPtr<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    void<\/span><span class=\"z-keyword\"> operator<\/span><span class=\"z-source\">()<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">As<\/span><span class=\"z-punctuation\">...<\/span><span class=\"z-variable z-parameter\"> args<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-source\">fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-entity z-name z-function\"> fn_ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">ctx<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> args...<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0430 \u0437\u0434\u0435\u0441\u044c \u2014 \u0432\u0442\u043e\u0440\u043e\u0439<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0445\u043e\u0442\u0435\u043b \u0447\u0435\u0441\u0442\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043d\u043e \u0432\u044b\u0432\u043e\u0434 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e \u0441\u043b\u043e\u043c\u0430\u043b\u0441\u044f<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  template<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> A1<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-type\"> class<\/span><span class=\"z-punctuation\">...<\/span><span class=\"z-entity z-name z-type\"> As<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-storage z-type\"> struct<\/span><span class=\"z-entity z-name z-type\"> Cb2<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    using<\/span><span class=\"z-entity z-name z-type\"> FnPtr<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-scope-resolution z-cpp\"> cb<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-type\">FnPtr<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-entity z-name z-type\">A1<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-type\"> void<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> As...<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    void<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-source\"> ctx<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    FnPtr fn_ptr<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    Cb2<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-entity z-name z-function\"> ctx<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-constant z-language\">nullptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-function\"> fn_ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-constant z-language\">nullptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    Cb2<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">FnPtr<\/span><span class=\"z-variable z-parameter\"> fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-entity z-name z-function\"> ctx<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-constant z-language\">nullptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-function\"> fn_ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    template<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> C<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-entity z-name z-function\"> Cb2<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">C<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-source\"> ctx<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-scope-resolution z-cpp\"> cb<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">FnPtr<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">A1<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> C<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> As...<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      :<\/span><span class=\"z-entity z-name z-function\"> ctx<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-keyword z-operator\">static_cast<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-storage z-type\">void<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">ctx<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      ,<\/span><span class=\"z-entity z-name z-function\"> fn_ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-keyword z-operator\">reinterpret_cast<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">FnPtr<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    void<\/span><span class=\"z-keyword\"> operator<\/span><span class=\"z-source\">()<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">A1<\/span><span class=\"z-variable z-parameter\"> a1<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> As<\/span><span class=\"z-punctuation\">...<\/span><span class=\"z-variable z-parameter\"> args<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-source\">fn_ptr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-entity z-name z-function\"> fn_ptr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">a1<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> ctx<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> args...<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>\u041a\u0440\u043e\u043c\u0435 \u044d\u0442\u043e\u0433\u043e, \u0432 \u0441\u0430\u043c\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0438\u0445 \u043a\u043e\u043b\u0431\u0435\u043a\u0438, \u0442\u043e\u0436\u0435 \u0435\u0441\u0442\u044c \u043d\u0435\u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c: \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043a\u043e\u043b\u0431\u0435\u043a \u0441 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u2014 \u044d\u0442\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b, \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435\u0442, \u0432 \u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u0441\u0442\u043e\u0438\u0442 \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u044f \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0431\u0435\u0440\u0442\u043a\u0438. \u0412\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-modifier\">inline<\/span><span class=\"z-storage z-type\"> auto<\/span><span class=\"z-entity z-name z-function\"> alloc_cb<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">Type<\/span><span class=\"z-variable z-parameter\"> type<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> Cb<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-variable z-parameter\"> cb<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-entity z-name z-function\"> alloc<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">cb<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-source\">fn_ptr<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> cb<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-source\">ctx<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">inline<\/span><span class=\"z-storage z-type\"> auto<\/span><span class=\"z-entity z-name z-function\"> set_draw_callback_cb2<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">ViewPort<\/span><span class=\"z-storage z-modifier\"> *<\/span><span class=\"z-variable z-parameter\">vp<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> Cb2<\/span><span class=\"z-punctuation\">&lt;<\/span><span class=\"z-entity z-name z-type\">Canvas<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">&gt;<\/span><span class=\"z-variable z-parameter\"> cb2<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-entity z-name z-function\"> set_draw_callback<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">vp<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> cb2<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-source\">fn_ptr<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> cb2<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-source\">ctx<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043a\u0430\u043a-\u0442\u043e \u0442\u0430\u043a:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0441\u043e \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">set_draw_callback_cb2<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">_vp<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> {<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> _draw}<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0441 \u043b\u044f\u043c\u0431\u0434\u043e\u0439 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0441\u0430\u0445\u0430\u0440\u043e\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">_timer <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-entity z-name z-scope-resolution z-cpp\"> timer<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-entity z-name z-function\">alloc_cb<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Periodic<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Ctx{<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">} <\/span><span class=\"z-keyword z-operator\">&gt;&gt;<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-punctuation\">[<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-entity z-name z-type\">SecondTimer<\/span><span class=\"z-storage z-modifier\"> *<\/span><span class=\"z-variable z-parameter\">self<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-source\"> self<\/span><span class=\"z-punctuation\">-&gt;<\/span><span class=\"z-entity z-name z-function\">_on_tick<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation\"> }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><h2 id=\"zakliuchenie\"><a class=\"anchor\" href=\"#zakliuchenie\" title=\"link to section\">#<\/a>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u042d\u0442\u043e \u0431\u044b\u043b\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0432 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0424\u043b\u0438\u043f\u043f\u0435\u0440\u0430 \u043c\u043d\u0435 \u043f\u043e\u043c\u043e\u0433 \u0421\u0438-\u0441-\u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 \u2014 \u0430 \u0442\u043e\u0447\u043d\u0435\u0435, \u043f\u043e\u0447\u0442\u0438 \u0431\u0435\u0437 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u043d\u043e \u0441 \u043d\u0435\u0439\u043c\u0441\u043f\u0435\u0439\u0441\u0430\u043c\u0438, RAII \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435. \u0415\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0435\u0441\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/furi-cpp\">\u0432 \u043c\u043e\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a> \u2014 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u043e\u0442 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/furi-cpp\/blob\/7e7536ab\/app\/app.hh#L93-L140\">\u043c\u0430\u0442\u0447\u0438\u043d\u0433 \u043f\u043e \u0442\u0438\u043f\u0430\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0439<\/a> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>std::variant<\/code>. \u041e\u0434\u043d\u0430\u043a\u043e \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0438\u0445 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e C++ \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u0432 \u043e\u043a\u043e\u043b\u043e-\u044d\u043c\u0431\u0435\u0434\u0434\u0435\u0434 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0439 \u043c\u0435\u0440\u0435, \u0435\u0441\u043b\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e.<\/p>\n"},{"title":"\u041a\u0430\u043a \u044f \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 3D-\u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u041b\u0435\u0433\u043e \u0443 \u0441\u0435\u0431\u044f \u043d\u0430 \u0441\u0430\u0439\u0442\u0435","published":"2023-09-08T00:00:00+00:00","updated":"2023-09-08T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/zmbx2gltf-ru\/"}},"id":"https:\/\/iliazeus.lol\/articles\/zmbx2gltf-ru\/","content":"<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434 \u043c\u043d\u0435 \u043d\u0430 \u0434\u0435\u043d\u044c \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0430\u0440\u0438\u043b\u0438 \u0442\u043e, \u043e \u0447\u0435\u043c \u044f \u043c\u0435\u0447\u0442\u0430\u043b \u0441 \u0434\u0435\u0442\u0441\u0442\u0432\u0430 \u2014 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043a\u043e\u0440\u043e\u0431\u043a\u0443 \u0441 \u043a\u0443\u0447\u0435\u0439 \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u041b\u0435\u0433\u043e, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e. \u041c\u043e\u0439 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0440\u0435\u0431\u0435\u043d\u043e\u043a \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u0447\u0430\u043b \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0438\u0437 \u043d\u0438\u0445 \u043c\u0430\u0448\u0438\u043d\u043a\u0438, \u0430 \u043c\u043e\u0439 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0432\u0437\u0440\u043e\u0441\u043b\u044b\u0439 \u0437\u0430\u0434\u0443\u043c\u0430\u043b\u0441\u044f \u2014 \u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u0438\u0445 \u043a\u0430\u043a-\u0442\u043e \u0443\u0432\u0435\u043a\u043e\u0432\u0435\u0447\u0438\u0442\u044c \u0432 \u0446\u0438\u0444\u0440\u043e\u0432\u043e\u043c \u0432\u0438\u0434\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0442\u043e\u043c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0441\u043d\u043e\u0432\u0430, \u0438 \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0432\u0441\u0435\u043c \u0434\u0440\u0443\u0437\u044c\u044f\u043c.<\/p>\n<p>\u042f \u043f\u0435\u0440\u0435\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u043e\u0432 3D-\u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u041b\u0435\u0433\u043e (\u043c\u043e\u0438\u043c \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u0443\u0441\u043b\u043e\u0432\u0438\u0435\u043c \u0431\u044b\u043b\u0430 \u0440\u0430\u0431\u043e\u0442\u0430 \u043d\u0430 Linux, \u043b\u0438\u0431\u043e \u0432 \u0432\u0435\u0431\u0435), \u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f \u043d\u0430 \u043e\u043d\u043b\u0430\u0439\u043d-\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.mecabricks.com\/\">Mecabricks<\/a>. \u041d\u043e, \u0443\u0436\u0435 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u044f \u0442\u0443\u0434\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043c\u043e\u0438\u0445 \u0442\u0432\u043e\u0440\u0435\u043d\u0438\u0439, \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \"\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0432\u0441\u0435\u043c \u0434\u0440\u0443\u0437\u044c\u044f\u043c\" \u0432\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u0435\u0435: \u0443 Mecabricks \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u043a\u0443\u0434\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430, \u0430 \u0435\u0433\u043e \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c <code>.zmbx<\/code> \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043d \u0438 \u0435\u0433\u043e \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f Blender.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u043a\u0430\u043a \u044d\u0442\u043e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442 \u0443\u0441\u0442\u0440\u043e\u0435\u043d, \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0435\u0440 \u0432\u043e \u0447\u0442\u043e-\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u043e\u0431\u0449\u0435\u043f\u0440\u0438\u043d\u044f\u0442\u043e\u0435. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u044f \u0432\u044b\u0431\u0440\u0430\u043b glTF, \u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043d\u0435\u0437\u0430\u0442\u0435\u0439\u043b\u0438\u0432\u043e \u043d\u0430\u0437\u0432\u0430\u043b <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2glTF\"><code>zmbx2gltf<\/code><\/a>. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b \u044d\u0442\u043e\u0442 \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439 <code>.zmbx<\/code>, \u043f\u0440\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0438 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 glTF \u043a\u0430\u043a \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 3D-\u0430\u0441\u0441\u0435\u0442\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438, \u0438 \u043f\u0440\u043e \u0442\u043e, \u043a\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u044f \u0440\u0435\u0448\u0430\u043b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u044f \u043e\u0434\u043d\u043e \u0432 \u0434\u0440\u0443\u0433\u043e\u0435.<\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 <code>zmbx2glTF<\/code> \u0435\u0441\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2glTF\">\u043d\u0430 GitHub<\/a>, \u0430 3D-\u043c\u043e\u0434\u0435\u043b\u044c\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"\/legos\/\">\u0443 \u043c\u0435\u043d\u044f \u043d\u0430 \u0441\u0430\u0439\u0442\u0435<\/a>.<\/p>\n<figure class=\"border\">\n<img src=\"cover.png\" alt=\"\" \/>\n<figcaption>\u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u041b\u0435\u0433\u043e, \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0435\u0439 \u0443\u0442\u0438\u043b\u0438\u0442\u043e\u0439<\/figcaption>\n<\/figure>\n<h2 id=\"chast-1-razbiraem-zmbx\"><a class=\"anchor\" href=\"#chast-1-razbiraem-zmbx\" title=\"link to section\">#<\/a>\u0427\u0430\u0441\u0442\u044c 1: \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c <code>.zmbx<\/code><\/h2>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e, \u0447\u0442\u043e \u043c\u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u044f\u0441\u043d\u0438\u0442\u044c \u043f\u0440\u043e \u044d\u0442\u043e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2glTF\/blob\/6729df3e\/src\/mbx\/types.ts\">\u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a> <code>zmbx2glTF<\/code>, \u0432 \u0432\u0438\u0434\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 TypeScript. \u0417\u0434\u0435\u0441\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0442\u043e, \u043a\u0430\u043a \u043c\u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u0432\u044b\u044f\u0441\u043d\u0438\u0442\u044c.<\/p>\n<h3 id=\"obshchaia-struktura\"><a class=\"anchor\" href=\"#obshchaia-struktura\" title=\"link to section\">#<\/a>\u041e\u0431\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u043c\u043d\u0435 \u0432 Unix-\u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0444\u0430\u0439\u043b \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0433\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u0442\u043e \u043f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u044f \u0434\u0435\u043b\u0430\u044e \u2014 \u0441\u043a\u0430\u0440\u043c\u043b\u0438\u0432\u0430\u044e \u0435\u0433\u043e \u0443\u0442\u0438\u043b\u0438\u0442\u0435 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/linux.die.net\/man\/1\/file\"><code>file<\/code><\/a>. \u041e\u043d\u0430 \u0443\u043c\u0435\u0435\u0442 \u043f\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c \"\u0432\u043e\u043b\u0448\u0435\u0431\u043d\u044b\u043c \u0447\u0438\u0441\u043b\u0430\u043c\" \u0438 \u043f\u0440\u043e\u0447\u0438\u043c \u043a\u043e\u0441\u0432\u0435\u043d\u043d\u044b\u043c \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u0430\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u0444\u0430\u0439\u043b\u043e\u0432. \u0414\u043b\u044f \u043c\u043e\u0435\u0433\u043e <code>.zmbx<\/code> \u043e\u043d\u0430 \u0432\u044b\u0432\u0435\u043b\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>$ file cab.zmbx<\/span><\/span>\n<span class=\"giallo-l\"><span>cab.zmbx: Zip archive data, at least v1.0 to extract, compression method=deflate<\/span><\/span><\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b <code>.zmbx<\/code> \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f ZIP-\u0430\u0440\u0445\u0438\u0432\u043e\u043c. \u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u0431\u0443\u043a\u0432\u0430 <code>z<\/code> \u0432 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u044d\u0442\u043e, \u0430 <code>mbx<\/code> \u2014 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043e\u0442 Mecabricks.<\/p>\n<p>\u0417\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u044c \u044d\u0442\u043e\u0433\u043e \u0430\u0440\u0445\u0438\u0432\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>$ unzip cab.zmbx<\/span><\/span>\n<span class=\"giallo-l\"><span>Archive:  cab.zmbx<\/span><\/span>\n<span class=\"giallo-l\"><span>  inflating: scene.mbx<\/span><\/span><\/code><\/pre>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043b\u043e\u0441\u044c: \u043d\u0435\u0441\u0436\u0430\u0442\u044b\u0439 \u0444\u0430\u0439\u043b \u0432\u043d\u0443\u0442\u0440\u0438 \u0438\u043c\u0435\u0435\u0442 \u043a\u0430\u043a \u0440\u0430\u0437 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 <code>.mbx<\/code>. \u041f\u0435\u0440\u0435\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u043e\u0432, \u044f \u0432\u044b\u044f\u0441\u043d\u0438\u043b, \u0447\u0442\u043e \u0432 \u0430\u0440\u0445\u0438\u0432\u0435 \u043e\u043d, \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0434\u0438\u043d, \u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0438\u043c\u0435\u0435\u0442 \u0438\u043c\u044f <code>scene.mbx<\/code>.<\/p>\n<p>\u0410 \u0447\u0442\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0433\u043e \u0441\u0430\u043c\u043e\u0433\u043e?<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>$ file scene.mbx<\/span><\/span>\n<span class=\"giallo-l\"><span>scene.mbx: JSON text data<\/span><\/span><\/code><\/pre>\n<p>\u041a\u0430\u0436\u0435\u0442\u0441\u044f, \u043d\u0430\u043c \u043f\u043e\u0432\u0435\u0437\u043b\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0437! \u0424\u043e\u0440\u043c\u0430\u0442 <code>.mbx<\/code> \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 JSON, \u0430 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043f\u0440\u0435\u043f\u0430\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0447\u0443\u0442\u044c \u043b\u0435\u0433\u0447\u0435, \u0447\u0435\u043c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0439 \u0444\u0430\u0439\u043b.<\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0437\u0431\u043e\u0440\u0430 \u043d\u0435\u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0445 JSON (\u0434\u0430 \u0438 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0445 \u0442\u043e\u0436\u0435) \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e Visual Studio Code. \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u0444\u0438\u0447\u0430 \"\u0441\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u0441\u0435 \u0431\u043b\u043e\u043a\u0438 \u043a\u043e\u0434\u0430, \u043d\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c\". \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0441 \u0437\u0430\u0436\u0430\u0442\u044b\u043c <code>Shift<\/code> \u043d\u0430\u0436\u0430\u0442\u044c \u043d\u0430 \u0441\u0442\u0440\u0435\u043b\u043e\u0447\u043a\u0443 \u0441\u043b\u0435\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u043b\u043e\u043a\u0438 \u043e\u0431\u044b\u0447\u043d\u043e \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f. \u041f\u0435\u0440\u0435\u0434 \u044d\u0442\u0438\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c VS Code, \u0447\u0442\u043e <code>.mbx<\/code> \u2014 \u044d\u0442\u043e \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 JSON (<code>F1 - Change Language Mode - JSON<\/code>), \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u0430 \u043a\u043e\u0434\u0430.<\/p>\n<figure class=\"border\">\n<img src=\"screenshot-1.png\" alt=\"\" \/>\n<figcaption>\u0412\u043e\u0442 \u0442\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0444\u0430\u0439\u043b \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u0438\u0445 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439<\/figcaption>\n<\/figure>\n<p>\u0412 \u043f\u043e\u043b\u0435 <code>metadata<\/code> \u2014 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0444\u0430\u0439\u043b\u0435.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"json\"><span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0432\u0441\u0435, \u043e \u0447\u0435\u043c \u044f \u0433\u043e\u0432\u043e\u0440\u044e, \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">version<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-constant z-numeric\">2<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">date<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">2023-01-11T09:43:49.552Z<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">generator<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">mecabricks<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> \u043e \u0434\u0440\u0443\u0433\u0438\u0445 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u0445 \u043c\u043d\u0435 \u043d\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0418\u0437 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0432\u0435\u0440\u0445\u043d\u0435\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u043b\u044e\u0441-\u043c\u0438\u043d\u0443\u0441 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0442\u043e\u043b\u044c\u043a\u043e <code>geometries<\/code> \u0438 <code>textures<\/code>. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043d\u0438\u0445.<\/p>\n<h3 id=\"tekstury\"><a class=\"anchor\" href=\"#tekstury\" title=\"link to section\">#<\/a>\u0422\u0435\u043a\u0441\u0442\u0443\u0440\u044b<\/h3>\n<p>\u041e\u0431\u044a\u0435\u043a\u0442 <code>textures<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0432\u0430 \u043f\u043e\u043b\u044f \u2014 <code>1<\/code> \u0438 <code>2<\/code>. \u042f \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u043e\u043c\u0435\u0440\u0430 \u0432\u0435\u0440\u0441\u0438\u0439 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u0435\u0439. \u0412\u043e \u0432\u0441\u0435\u0445 \u043c\u043e\u0438\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u0445 \u043e\u043d\u0438 \u043e\u0442\u043b\u0438\u0447\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043c, \u0447\u0442\u043e \u0432 \u0432\u0435\u0440\u0441\u0438\u0438 <code>2<\/code> \u0435\u0441\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 <code>official<\/code>- \u0438 <code>custom<\/code>-\u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b.<\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u0432\u0441\u0435 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e: \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u044b \u043d\u0430 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438 (<code>bump<\/code>\/<code>normal<\/code>\/<code>mask<\/code>\/<code>color<\/code>\/<code>data<\/code>), \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u0439 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438 \u2014 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \"\u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u2192 base64-\u0434\u0430\u043d\u043d\u044b\u0435\". \u0424\u0430\u0439\u043b\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u0438\u043c\u0435\u043b\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 <code>.png<\/code>, \u0430 \u0444\u043e\u0440\u043c\u0430\u0442 base64-\u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043c\u043e\u0438\u043c \u043b\u044e\u0431\u0438\u043c\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>$ (base64 -d | file -) &lt;&lt;EOF<\/span><\/span>\n<span class=\"giallo-l\"><span>iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPm...<\/span><\/span>\n<span class=\"giallo-l\"><span>EOF<\/span><\/span>\n<span class=\"giallo-l\"><span>\/dev\/stdin: PNG image data, 128 x 128, 8-bit\/color RGBA, non-interlaced<\/span><\/span><\/code><\/pre>\n<p>\u0421 <code>color<\/code>, <code>bump<\/code>, <code>normal<\/code> \u0438 <code>metalness<\/code> \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438 \u0432\u0441\u0435 \u0431\u043e\u043b\u0435\u0435-\u043c\u0435\u043d\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e; \u0440\u0430\u0437\u0431\u043e\u0440 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u044f \u0440\u0435\u0448\u0438\u043b \u043e\u0442\u043b\u043e\u0436\u0438\u0442\u044c \u043d\u0430 \u043f\u043e\u0442\u043e\u043c.<\/p>\n<h3 id=\"geometriia\"><a class=\"anchor\" href=\"#geometriia\" title=\"link to section\">#<\/a>\u0413\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f<\/h3>\n<p>\u041f\u043e\u043b\u0435 <code>geometries<\/code> \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0435\u043b\u0435\u043d\u043e \u043d\u0430 \u0434\u0432\u0435 \u0432\u0435\u0440\u0441\u0438\u0438, \u043d\u043e \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u043c\u043d\u0435 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438 \u0437\u043d\u0430\u0447\u0438\u043c\u044b\u0445 \u043e\u0442\u043b\u0438\u0447\u0438\u0439. \u0417\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043e\u0434\u043d\u043e\u0433\u043e: \u0432 \u0432\u0435\u0440\u0441\u0438\u0438 <code>1<\/code> \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <code>metadata<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"json\"><span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">version<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 3<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">type<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">Geometry<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">vertices<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 704<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">generator<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">io_three<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">faces<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 352<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">normals<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 162<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u041f\u043e\u043b\u0435 <code>generator<\/code> \u0434\u0430\u043b\u043e \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0443: <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/repsac\/io_three\"><code>io_three<\/code><\/a> \u2014 \u044d\u0442\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u0438\u0437 Blender \u0432 \u0444\u043e\u0440\u043c\u0430\u0442, \u043f\u0440\u0438\u0433\u043e\u0434\u043d\u044b\u0439 \u0434\u043b\u044f <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/threejs.org\/\"><code>three.js<\/code><\/a>. \u041f\u043e \u043a\u043e\u0434\u0443 \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e, \u043c\u0430\u0441\u0441\u0438\u0432 <code>faces<\/code> \u0445\u0440\u0430\u043d\u0438\u0442 \u0432\u0441\u0435 \u0433\u0440\u0430\u043d\u0438 \u0432 \u0442\u0430\u043a\u043e\u043c \u0432\u0438\u0434\u0435: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0447\u0438\u0441\u043b\u043e, \u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0449\u0435\u0435 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2glTF\/blob\/6729df3e\/src\/mbx\/types.ts#L122\">\u0444\u043b\u0430\u0433\u0438<\/a>: \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0430\u044f \u0433\u0440\u0430\u043d\u044c \u0438\u043b\u0438 \u0447\u0435\u0442\u044b\u0440\u0435\u0445\u0443\u0433\u043e\u043b\u044c\u043d\u0430\u044f, \u0435\u0441\u0442\u044c \u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044f\u0445, UV-\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 \u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u0445; \u0437\u0430\u0442\u0435\u043c \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0432 \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u044b \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d, \u043d\u043e\u0440\u043c\u0430\u043b\u0435\u0439 \u0438 UV-\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442.<\/p>\n<h3 id=\"detali-i-konfiguratsii\"><a class=\"anchor\" href=\"#detali-i-konfiguratsii\" title=\"link to section\">#<\/a>\u0414\u0435\u0442\u0430\u043b\u0438 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438<\/h3>\n<p><em>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/em> (<code>configuration<\/code>) \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u2014 \u043c\u043e\u0434\u0435\u043b\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0434\u0435\u0442\u0430\u043b\u0438, \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u044b\u043c\u0438 \u043a \u043d\u0435\u0439 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0443\u043a\u0440\u0430\u0448\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0430\u043c\u0438, \u0432\u0440\u043e\u0434\u0435 \u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u0439 \u0438 \u043b\u043e\u0433\u043e\u0442\u0438\u043f\u043e\u0432 Lego. \u0422\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044e \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0447\u0430\u0441\u0442\u0435\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u2014 \u0432 \u043f\u043e\u043b\u0435 \u0444\u0430\u0439\u043b\u0430 <code>details<\/code> \u0432 \u043a\u043e\u0440\u043d\u0435 \u0444\u0430\u0439\u043b\u0430 \u2014 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043e \u0432\u0441\u0435\u0445 \u0434\u0435\u0442\u0430\u043b\u044f\u0445.<\/p>\n<p>\u0412\u0435\u0440\u0441\u0438\u0439 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 \u0442\u043e\u0436\u0435 \u0434\u0432\u0435, \u043d\u043e \u0438\u0437 \u0437\u043d\u0430\u0447\u0438\u043c\u044b\u0445 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u0439 \u0431\u044b\u043b \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u0439\u043c\u0438\u043d\u0433: \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0432\u0435\u0440\u0441\u0438\u0438 1 \u043d\u0430\u0437\u0432\u0430\u043d\u044b \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <code>&lt;id&gt;.json<\/code>, \u0432\u0435\u0440\u0441\u0438\u0438 2 \u2014 \u043f\u0440\u043e\u0441\u0442\u043e <code>&lt;id&gt;<\/code>.<\/p>\n<p><em>\u0414\u0435\u0442\u0430\u043b\u044c<\/em> (<code>part<\/code>) \u0432 \u044d\u0442\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u2014 \u0443\u0436\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0434\u0435\u0442\u0430\u043b\u0438, \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u043c \u0438 \u043c\u0430\u0442\u0440\u0438\u0446\u0435\u0439 \u0430\u0444\u0444\u0438\u043d\u043d\u043e\u0439 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 (row-major). \u041e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u0434\u0435\u0442\u0430\u043b\u0435\u0439.<\/p>\n<h3 id=\"materialy\"><a class=\"anchor\" href=\"#materialy\" title=\"link to section\">#<\/a>\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b<\/h3>\n<p>\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0431\u044b\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u0444\u0430\u0439\u043b\u0435. \u0412\u043c\u0435\u0441\u0442\u043e \u043d\u0438\u0445 \u0442\u0430\u043c \u0431\u044b\u043b\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0445 \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0435 id. \u042f \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0441\u044f \u0433\u0443\u0433\u043b\u0438\u0442\u044c, \u043d\u0430\u0448\u0435\u043b \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0430\u0445 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u043a\u0443\u0434\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0446\u0432\u0435\u0442\u043e\u0432 \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u041b\u0435\u0433\u043e \u2014 \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435, \u0443 \u0432\u0441\u0435\u0445 \u0431\u044b\u043b\u0438 \u0440\u0430\u0437\u043d\u044b\u0435 id. \u041f\u0443\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0430, \u043d\u0430\u0448\u0435\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/pnichols04\/lego_colors\">pnichols04\/lego_colors<\/a> \u043d\u0430 GitHub. \u041f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0435 \u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e-\u0434\u0440\u0443\u0433\u043e\u043c\u0443, \u0442\u0435\u043f\u0435\u0440\u044c \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0438 \u0432 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2glTF\/blob\/6729df3e\/src\/convert\/data\/colors.ts\">\u043c\u043e\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>.<\/p>\n<h2 id=\"chast-2-vybiraem-kuda-konvertirovat\"><a class=\"anchor\" href=\"#chast-2-vybiraem-kuda-konvertirovat\" title=\"link to section\">#<\/a>\u0427\u0430\u0441\u0442\u044c 2: \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c, \u043a\u0443\u0434\u0430 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c<\/h2>\n<p>\u0412 \u043c\u0438\u0440\u0435 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 3D-\u043c\u043e\u0434\u0435\u043b\u0435\u0439. \u041a\u0430\u043a\u043e\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u043c\u043d\u0435 \u043d\u0443\u0436\u0435\u043d, \u043c\u043d\u0435 \u043d\u0435 \u0431\u044b\u043b\u043e \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u2014 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u043b\u0435\u043a \u043e\u0442 \u0441\u0444\u0435\u0440\u044b 3D-\u0433\u0440\u0430\u0444\u0438\u043a\u0438. \u041d\u043e \u044f \u043d\u0430\u043c\u0435\u0442\u0438\u043b \u043a \u043d\u0435\u043c\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439:<\/p>\n<ul>\n<li>\n<p>\u0411\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0448\u0438\u0440\u043e\u043a\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u043c.<\/p>\n<p>\u041c\u043e\u0438\u043c\u0438 \u0433\u043b\u0430\u0432\u043d\u044b\u043c\u0438 \u0446\u0435\u043b\u044f\u043c\u0438 \u0432\u0441\u0435 \u0435\u0449\u0435 \u0431\u044b\u043b\u0438 \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u043d\u0430 \u043c\u043e\u0435\u043c \u0441\u0430\u0439\u0442\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0447\u0442\u043e-\u0442\u043e, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u0443\u0436\u0435 \u0431\u044b\u043b\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0449\u0438\u043a\u0438, \u0438 \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u043b\u0435\u0433\u043a\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u043e\u0444\u0442.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043c\u0435\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435.<\/p>\n<p>\u0422\u0443\u0442 \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e: \u043c\u043d\u0435 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0440\u0435\u0432\u0435\u0440\u0441-\u0438\u043d\u0436\u0438\u043d\u0438\u0440\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0444\u043e\u0440\u043c\u0430\u0442.<\/p>\n<\/li>\n<li>\n<p>\u0411\u044b\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u043c, \u043b\u0438\u0431\u043e \u0438\u043c\u0435\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0449\u0435 \u043e\u0442\u043b\u0430\u0436\u0438\u0432\u0430\u0442\u044c. \u041a\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u0443\u0431\u0435\u0434\u0438\u043b\u0438\u0441\u044c \u0432 \u0447\u0430\u0441\u0442\u0438 1, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u044e\u0431\u043e\u0439 IDE, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043b\u0435\u0437\u0442\u044c \u043a \u043d\u0438\u043c \u0432\u043d\u0443\u0442\u0440\u044c \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u043d\u0435 \u0442\u0430\u043a.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438.<\/p>\n<p>\u0412 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c <code>.mbx<\/code> \u0432\u0441\u044f \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u043c\u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u0432 \u0446\u0435\u043b\u0435\u0432\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0431\u044b\u043b\u043e \u0442\u0430\u043a \u0436\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b (specular, normal, bump) \u043a\u0430\u043a \u0447\u0430\u0441\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430.<\/p>\n<p>\u042d\u0442\u043e \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u2014 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u043e\u0434\u043d\u043e\u0442\u043e\u043d\u043d\u044b\u0435 \u2014 \u043d\u043e \u0441 \u043d\u0438\u043c\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u043a\u0440\u0430\u0441\u0438\u0432\u0435\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u043e\u0439\u0434\u044f\u0441\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/en.wikipedia.org\/wiki\/List_of_file_formats#3D_graphics\">\u043f\u043e \u0441\u043f\u0438\u0441\u043a\u0443 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432<\/a> \u043d\u0430 \u0412\u0438\u043a\u0438\u043f\u0435\u0434\u0438\u0438, \u044f \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043c\u043d\u0435 \u0444\u043e\u0440\u043c\u0430\u0442: <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/en.wikipedia.org\/wiki\/glTF\">glTF<\/a>. \u041e\u043d \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u043b \u043f\u043e\u0434 \u0432\u0441\u0435 \u043c\u043e\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f. \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0435\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u0430\u044f \u0444\u043e\u0440\u043c\u0430 \u0431\u044b\u043b\u0430 \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e: \u044d\u0442\u043e JSON-\u0444\u0430\u0439\u043b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u2014 \u043c\u0435\u0448\u0438, \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b, \u0443\u0437\u043b\u044b \u0433\u0440\u0430\u0444\u0430 \u0441\u0446\u0435\u043d\u044b; \u0435\u0441\u043b\u0438 \u0438\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u0434\u0440\u0443\u0433 \u043d\u0430 \u0434\u0440\u0443\u0433\u0430, \u043e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0432 \u044d\u0442\u0438\u0445 \u043c\u0430\u0441\u0441\u0438\u0432\u0430\u0445.<\/p>\n<p>\u0414\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u0430\u044f \u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f glTF \u0435\u0441\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/KhronosGroup\/glTF\">\u0432 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>; \u043c\u043e\u0436\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u0433\u043b\u044f\u043d\u0443\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\/blob\/6729df3e\/src\/gltf\/types.ts\">\u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a> \u043a\u043e \u043c\u043d\u0435 \u2014 \u0442\u0430\u043c \u0435\u0441\u0442\u044c TypeScript-\u0442\u0438\u043f\u044b \u0434\u043b\u044f JSON-\u0444\u043e\u0440\u043c\u044b glTF. \u0417\u0434\u0435\u0441\u044c \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0435\u0433\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e; \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043b\u0438\u0448\u044c \u043e \u0437\u043d\u0430\u0447\u0438\u043c\u044b\u0445 \u043e\u0442\u043b\u0438\u0447\u0438\u044f\u0445 \u0435\u0433\u043e \u043e\u0442 <code>.mbx<\/code>, \u0438 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0438 \u0443 \u043c\u0435\u043d\u044f \u043f\u0440\u0438 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438.<\/p>\n<h2 id=\"chast-3-iz-mbx-v-gltf\"><a class=\"anchor\" href=\"#chast-3-iz-mbx-v-gltf\" title=\"link to section\">#<\/a>\u0427\u0430\u0441\u0442\u044c 3: \u0438\u0437 <code>.mbx<\/code> \u0432 glTF<\/h2>\n<h3 id=\"matritsy-transformatsii\"><a class=\"anchor\" href=\"#matritsy-transformatsii\" title=\"link to section\">#<\/a>\u041c\u0430\u0442\u0440\u0438\u0446\u044b \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438<\/h3>\n<p>\u041a\u0430\u043a \u044f \u043f\u0438\u0441\u0430\u043b \u0432\u044b\u0448\u0435, \u0432 <code>.mbx<\/code> \u043c\u0430\u0442\u0440\u0438\u0446\u044b \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0437\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0438\u0437 16 \u0447\u0438\u0441\u0435\u043b, \u0432 row-major \u043f\u043e\u0440\u044f\u0434\u043a\u0435. glTF \u0436\u0435 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/registry.khronos.org\/glTF\/specs\/2.0\/glTF-2.0.html#data-alignment\">\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442<\/a> column-major \u043f\u043e\u0440\u044f\u0434\u043e\u043a. \u041f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043e\u0434\u0438\u043d \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u2014 \u043d\u0443\u0436\u043d\u043e <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\/blob\/6729df3e\/src\/convert\/utils.ts#L9\">\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c<\/a> \u043c\u0430\u0442\u0440\u0438\u0446\u0443.<\/p>\n<h3 id=\"png-kartinki-v-base64\"><a class=\"anchor\" href=\"#png-kartinki-v-base64\" title=\"link to section\">#<\/a>PNG-\u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0432 Base64<\/h3>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 <code>.mbx<\/code> \u0432\u0441\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f-\u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0437\u0430\u0434\u0430\u043d\u044b \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 PNG \u0438 \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 Base64. glTF \u0442\u043e\u0436\u0435 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/registry.khronos.org\/glTF\/specs\/2.0\/glTF-2.0.html#images\">\u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442<\/a> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u043d\u043e \u0435\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u043e\u0444\u043e\u0440\u043c\u0438\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/en.wikipedia.org\/wiki\/Data_URI_scheme\">data URI<\/a>. \u0421\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0442\u043e\u0436\u0435 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u2014 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\/blob\/6729df3e\/src\/convert\/utils.ts#L3\">\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e<\/a> \u043f\u0440\u0435\u0444\u0438\u043a\u0441 <code>data:image\/png;base64,<\/code>.<\/p>\n<h3 id=\"tsveta-plius-dekali\"><a class=\"anchor\" href=\"#tsveta-plius-dekali\" title=\"link to section\">#<\/a>\u0426\u0432\u0435\u0442\u0430 \u043f\u043b\u044e\u0441 \u0434\u0435\u043a\u0430\u043b\u0438<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u041b\u0435\u0433\u043e \u0432 <code>.mbx<\/code>-\u0444\u0430\u0439\u043b\u0430\u0445 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0446\u0432\u0435\u0442, \u0438 \u0434\u0435\u043a\u0430\u043b\u044c (specular-\u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430). \u041e\u0431\u044b\u0447\u043d\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0446\u0432\u0435\u0442 \u2014 \u044d\u0442\u043e \u0446\u0432\u0435\u0442 \u043f\u043b\u0430\u0441\u0442\u0438\u043a \u0434\u0435\u0442\u0430\u043b\u0438, \u0430 \u0434\u0435\u043a\u0430\u043b\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430\u043a\u043b\u0435\u0439\u043a\u0443 \u043d\u0430 \u043d\u0435\u0439. \u0412 glTF <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/registry.khronos.org\/glTF\/specs\/2.0\/glTF-2.0.html#metallic-roughness-material\">\u0441 \u044d\u0442\u0438\u043c \u0441\u0442\u0440\u043e\u0436\u0435<\/a> \u2014 \u043b\u0438\u0431\u043e \u0446\u0432\u0435\u0442, \u043b\u0438\u0431\u043e \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u043e\u0441\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\/blob\/6729df3e\/src\/convert\/materials.ts#L83\">\u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c PNG<\/a>, <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\/blob\/6729df3e\/src\/convert\/materials.ts#L88\">\u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0442\u044c<\/a> \u0435\u0433\u043e \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0446\u0432\u0435\u0442\u043e\u043c, \u0430 \u0437\u0430\u0442\u0435\u043c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\/blob\/6729df3e\/src\/convert\/materials.ts#L94\">\u0443\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0442\u044c<\/a> \u043e\u0431\u0440\u0430\u0442\u043d\u043e. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/pngjs\">PNG.js<\/a>.<\/p>\n<h3 id=\"nereshennaia-problema-bump-map-normal-map\"><a class=\"anchor\" href=\"#nereshennaia-problema-bump-map-normal-map\" title=\"link to section\">#<\/a>\u041d\u0435\u0440\u0435\u0448\u0435\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: bump map + normal map<\/h3>\n<p>\u041d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u0435\u0442\u0430\u043b\u044f\u0445 \u0432\u0438\u0441\u0438\u0442 \u0441\u0440\u0430\u0437\u0443 \u0438 bump map, \u0438 normal map; glTF \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e normal map. \u0412 \u0446\u0435\u043b\u043e\u043c, \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u0443\u044e \u0432\u043e \u0432\u0442\u043e\u0440\u0443\u044e \u0438 \u0441\u043c\u0435\u0448\u0430\u0442\u044c \u0438\u0445, \u0435\u0441\u043b\u0438 \u0431\u044b \u043d\u0435 \u043e\u0434\u043d\u043e \"\u043d\u043e\": UV-\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0442\u0435\u043a\u0441\u0442\u0443\u0440 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0440\u0430\u0437\u043d\u044b\u0435. \u0417\u0434\u0435\u0441\u044c \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0430\u0442\u044c\u0441\u044f; \u043a\u0430\u043a \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u043a\u0430\u043c\u0438, \u044f \u043d\u0435 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u043b.<\/p>\n<h3 id=\"udalenie-neispol-zuemykh-sushchnostei\"><a class=\"anchor\" href=\"#udalenie-neispol-zuemykh-sushchnostei\" title=\"link to section\">#<\/a>\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439<\/h3>\n<p>\u0418\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e \u043d\u0435 \u0432\u0441\u0435 \u0444\u0438\u0447\u0438 <code>.mbx<\/code>, \u0432 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u043f\u043e\u043f\u0430\u0434\u0430\u043b\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0438\u0433\u0434\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u044f \u043c\u043e\u0433 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c bump map, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u0435\u0433\u043e \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u042f \u0440\u0435\u0448\u0438\u043b \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0438\u0437 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. \u041d\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u0431\u0440\u0430\u0442\u044c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432: \u0442\u043e\u0433\u0434\u0430 \u043f\u043e\u0435\u0445\u0430\u043b\u0438 \u0431\u044b \u0438\u043d\u0434\u0435\u043a\u0441\u044b-\u0441\u0441\u044b\u043b\u043a\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\/blob\/6729df3e\/src\/gltf\/optimizer.ts#L21\">\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b<\/a> \u043e\u0431\u043e\u0431\u0449\u0435\u043d\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043f\u0435\u0440\u0435\u043d\u0443\u043c\u0435\u0440\u043e\u0432\u044b\u0432\u0430\u043d\u0438\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u044f \u043f\u043e\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0438\u0437 C++ \u0438\u0434\u0435\u044e \u0441\u0441\u044b\u043b\u043e\u043a, <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\/blob\/6729df3e\/src\/gltf\/optimizer.ts#L3\">\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0432<\/a> \u0438\u0445 \u043a\u0430\u043a \u043f\u0430\u0440\u0443 \"\u0433\u0435\u0442\u0442\u0435\u0440\"-\"\u0441\u0435\u0442\u0442\u0435\u0440\", \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0438 \u0445\u0440\u0430\u043d\u0438\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438 \u043a\u043b\u044e\u0447 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043d\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0438. \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0438\u0445 \u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\/blob\/6729df3e\/src\/gltf\/optimizer.ts#L56\">\u0434\u0435\u0434\u0443\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044f<\/a> \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u2014 \u043a\u0430\u043a \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u043e\u0434\u043d\u0430 \u0438 \u0442\u0430 \u0436\u0435 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0432 <code>.mbx<\/code>-\u0444\u0430\u0439\u043b\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0434\u043b\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0434\u0435\u0442\u0430\u043b\u0435\u0439.<\/p>\n<h2 id=\"itogi\"><a class=\"anchor\" href=\"#itogi\" title=\"link to section\">#<\/a>\u0418\u0442\u043e\u0433\u0438<\/h2>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435, \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2gltf\">\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442<\/a> \u0434\u043b\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f <code>.zmbx<\/code>-\u0444\u0430\u0439\u043b\u043e\u0432 \u0432 <code>.gltf<\/code>-\u0444\u0430\u0439\u043b\u044b. \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0448\u043b\u043e \u0441 \u043f\u043e\u0442\u0435\u0440\u044f\u043c\u0438, \u043d\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u043d\u0435 \u0431\u044b\u043b\u043e, \u0432 \u0446\u0435\u043b\u043e\u043c, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0414\u043b\u044f <a href=\"\/legos\/\">\u0441\u0432\u043e\u0435\u0433\u043e \u0441\u0430\u0439\u0442\u0430<\/a> \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/kovacsv\/Online3DViewer\">Online3DViewer<\/a>; \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0435\u0433\u043e \u043a\u0438\u043b\u043b\u0435\u0440-\u0444\u0438\u0447\u0435\u0439 \u0441\u0442\u0430\u043b\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u043d\u0438\u044f\u043c\u0438 \u0440\u0435\u0431\u0440\u0430 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u2014 \u043f\u043e\u0447\u0442\u0438 \u043a\u0430\u043a \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u0445 \u041b\u0435\u0433\u043e.<\/p>\n<p>\u0412 \u043f\u043b\u0430\u043d\u0435 \u0440\u0435\u0432\u0435\u0440\u0441-\u0438\u043d\u0436\u0438\u043d\u0438\u0440\u0438\u043d\u0433\u0430, <code>.zmbx<\/code> \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u043c, \u043d\u043e \u044d\u0442\u043e \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0431\u044b\u043b \u0446\u0435\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043e\u043f\u044b\u0442. \u042f \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/zmbx2glTF\/blob\/6729df3e\/src\/mbx\/types.ts\">\u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a> \u2014 \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u043d\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0435 \u2014 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0438 \u0434\u0440\u0443\u0433\u0438\u043c \u043b\u044e\u0434\u044f\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b.<\/p>\n"},{"title":"\u0420\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u044f \u0432 JavaScript \u0438 TypeScript: \u043e\u0431\u0437\u043e\u0440 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0442\u0435\u0445\u043d\u0438\u043a. \u041a\u0430\u043a \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430 CLI-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441","published":"2023-08-23T00:00:00+00:00","updated":"2023-08-23T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/js-ts-reflection-ru\/"}},"id":"https:\/\/iliazeus.lol\/articles\/js-ts-reflection-ru\/","content":"<p>\u041a\u0430\u043a \u0438 \u0432 \u043b\u044e\u0431\u043e\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435, \u0432 JavaScript \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u0435\u0441\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u2014 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0438\u043f\u044b, \u043a\u043b\u044e\u0447\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0438 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u044b.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0442\u0430\u043a\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u043f\u043b\u044e\u0441 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u0438\u043f\u0430\u0445 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 TypeScript, \u0438 \u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0441\u0430\u043c \u0438 \u0438\u0445 \u043f\u043e\u043b\u044f\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u043e\u0432. \u041a\u0430\u0436\u0434\u0443\u044e \u0438\u0437 \u0442\u0435\u0445\u043d\u0438\u043a \u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e CLI-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043a \u043a\u043e\u043d\u0446\u0443 \u0441\u0442\u0430\u0442\u044c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u0430\u043a \u043d\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435:<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/js-ts-reflection-ru\/cover.png\" alt=\"\u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 CLI-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\" \/><\/p>\n<p>\u0412\u0435\u0441\u044c \u043c\u043e\u0439 \u043e\u0431\u0437\u043e\u0440 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438 \u2014 \u0438 \u0432\u0441\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430\u0434 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u2014 \u044f \u0440\u0430\u0437\u0434\u0435\u043b\u044e \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0440\u043e\u0432\u043d\u0435\u0439.<\/p>\n<h2 id=\"uroven-0-nikakoi-refleksii\"><a class=\"anchor\" href=\"#uroven-0-nikakoi-refleksii\" title=\"link to section\">#<\/a>\u0423\u0440\u043e\u0432\u0435\u043d\u044c 0: \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u043e\u0434 \u0432\u043e\u043e\u0431\u0449\u0435 \u0431\u0435\u0437 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438 \u2014 \u043f\u043e \u0444\u0430\u043a\u0442\u0443, \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0434\u043b\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/nodejs.org\/docs\/latest-v20.x\/api\/util.html#utilparseargsconfig\"><code>util.parseArgs<\/code><\/a> \u0438\u0437 Node.js.<\/p>\n<details><summary>stage0\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> Main<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043e\u043f\u0446\u0438\u044f \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u0430<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043e\u043f\u0446\u0438\u044f-\u0444\u043b\u0430\u0433, \u0431\u0435\u0437 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043e\u043f\u0446\u0438\u044f \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043e\u043f\u0446\u0438\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">main<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Main<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-object z-property\"> positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-object z-property\"> values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u043a\u043e\u0433\u043e \u043d\u0435\u0434\u043e-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<details><summary>stage0\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">main<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435 \u0438\u043c\u0435\u043d\u0430<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-keyword z-operator\"> ||<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">v<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">commandArgs<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> args<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  switch<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    case<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">name<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> commandArgs<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">        console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">command required 1 argument, 0 given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0442\u0438\u043f\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043e\u043f\u0446\u0438\u0439<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">        console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    default<\/span><span class=\"z-punctuation\">:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>\u041a\u0430\u043a \u0445\u043e\u0440\u043e\u0448\u043e \u0432\u0438\u0434\u043d\u043e \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u0447\u0442\u0438 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c CLI-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441. \u041a\u043e\u0440\u043e\u0442\u043a\u0438\u0435 \u0438\u043c\u0435\u043d\u0430 \u043e\u043f\u0446\u0438\u0439, \u0442\u0438\u043f\u044b \u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u043e\u043c\u0430\u043d\u0434 \u2014 \u0432\u0441\u0435 \u044d\u0442\u043e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<p>\u042d\u0442\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u043d\u043d\u043e \u043c\u043e\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u2014 \u0441\u0430\u043c\u043e\u0439 <code>parseArgs<\/code> \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/nodejs.org\/docs\/latest-v20.x\/api\/util.html#utilparseargsconfig\">\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 CLI-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430<\/a> \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0432\u0441\u0435\u0445 \u043e\u043f\u0446\u0438\u0439. \u041d\u043e \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u0442\u0430\u043a\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435, \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u044e, \u043f\u043e\u0437\u0432\u043e\u043b\u044f \u0435\u043c\u0443 \u0441\u0430\u043c\u043e\u043c\u0443 \u0432\u044b\u0432\u0435\u0441\u0438\u0442 \u044d\u0442\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0443 \u0441 \u043e\u0441\u043d\u043e\u0432.<\/p>\n<h2 id=\"uroven-1-osnovy-js-refleksii\"><a class=\"anchor\" href=\"#uroven-1-osnovy-js-refleksii\" title=\"link to section\">#<\/a>\u0423\u0440\u043e\u0432\u0435\u043d\u044c 1: \u043e\u0441\u043d\u043e\u0432\u044b JS-\u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438<\/h2>\n<p>\u042d\u0442\u0438 \u0442\u0435\u0445\u043d\u0438\u043a\u0438 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u044b, \u0447\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043a JS \u0438\u0445 \u0440\u0435\u0434\u043a\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0435\u0439:<\/p>\n<ul>\n<li>\n<p><a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/typeof\">\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>typeof<\/code><\/a>: \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 JS-\u0442\u0438\u043f\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f<\/p>\n<p>\u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 <code>typeof x<\/code> \u043c\u043e\u0436\u0435\u0442 \u0432\u0435\u0440\u043d\u0443\u0442\u044c <code>\"undefined\"<\/code>, <code>\"boolean\"<\/code>, <code>\"number\"<\/code>, <code>\"bigint\"<\/code>, <code>\"string\"<\/code>, <code>\"object\"<\/code>, <code>\"function\"<\/code>. \u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u043e \u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c <code>typeof null === \"object\"<\/code>!<\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f <code>\"function\"<\/code>, \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u0438, \u0447\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u0430\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0438\u0445 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 <code>new<\/code>.<\/p>\n<\/li>\n<li>\n<p><a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/instanceof\">\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>instanceof<\/code><\/a>: \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435, \u0435\u0441\u0442\u044c \u043b\u0438 \u043d\u0443\u0436\u043d\u044b\u0439 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f \u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u0430<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0437\u0430\u0431\u044b\u0442\u044c \u043f\u0440\u043e \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u043d\u043e\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u0442\u043e <code>x instanceof A<\/code> \u0432\u0435\u0440\u043d\u0435\u0442 \u0431\u0443\u043b\u0435\u0432\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0435, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 <code>x<\/code> \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u043c <code>A<\/code> \u0438\u043b\u0438 \u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043c\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p><a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/in\">\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>in<\/code><\/a>: \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u043a\u043b\u044e\u0447\u0430 \u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u0430<\/p>\n<p>\u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f <code>\"p\" in x<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0435\u0441\u0442\u044c \u043b\u0438 \u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <code>x<\/code> \u043a\u043b\u044e\u0447 <code>p<\/code>. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c <code>x<\/code> \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c, \u0438\u043d\u0430\u0447\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043a\u0438\u043d\u0443\u0442\u0430 <code>TypeError<\/code>.<\/p>\n<\/li>\n<li>\n<p><a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/keys\">\u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>Object.keys()<\/code><\/a> \u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/for...in\">\u0446\u0438\u043a\u043b <code>for...in<\/code><\/a>: \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0439 \u043e\u0431\u044a\u0435\u043a\u0442\u0430<\/p>\n<p>\u042d\u0442\u0438\u043c\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u043a\u043b\u044e\u0447\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Enumerability_and_ownership_of_properties\">\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f\u0435\u043c\u044b\u043c\u0438 (enumerable)<\/a>. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0432 \u044d\u0442\u0443 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u043a\u043b\u044e\u0447\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0438\u0442\u044c. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u0434\u0430\u043b\u0435\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430\u0448 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0447\u0443\u0442\u044c \u043a\u0440\u0430\u0441\u0438\u0432\u0435\u0435. \u0410 \u0438\u043c\u0435\u043d\u043d\u043e: \u043f\u0443\u0441\u0442\u044c \u0442\u0435\u043f\u0435\u0440\u044c \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u043c, \u0430 \u0435\u0433\u043e \u043f\u043e\u043b\u044f \u0431\u0443\u0434\u0443\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u043e\u0431\u0449\u0438\u0435 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u0430\u043d\u0434 \u043e\u043f\u0446\u0438\u0438:<\/p>\n<details><summary>stage1\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  main<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">    args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">    opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  )<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-object z-property\"> positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-object z-property\"> values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u043e \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044e, \u0432\u0441\u0435 \u043f\u043e\u043b\u044f `program` - \u044d\u0442\u043e \u043e\u0431\u0449\u0438\u0435 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u0430\u043d\u0434 \u043e\u043f\u0446\u0438\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0435 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u044e, \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u043e<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0433\u043e\u0442\u043e\u0432\u044c\u0442\u0435\u0441\u044c \u2014 \u0432 \u043a\u043e\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 any<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      (<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>\u041a\u043e\u0434 \u0432 <code>main.ts<\/code> \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<details><summary>stage1\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0435\u0441\u043b\u0438 target \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u0442\u0430\u0440\u044b\u0439 (\u043c\u0435\u043d\u044c\u0448\u0435 es2022),<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0442\u043e \u0432 \u043d\u0435\u043c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043d\u0435 \u0437\u0430\u0434\u0430\u043d\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-undefined z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0434\u043b\u044f es2022 \u0438 \u043d\u043e\u0432\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  v<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435 \u0438\u043c\u0435\u043d\u0430 \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">v<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u0435\u0449\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">commandArgs<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> args<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    switch<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      case<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">name<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> commandArgs<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">          console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">command required 1 argument, 0 given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">          return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">        }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0442\u0438\u043f\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043e\u043f\u0446\u0438\u0439<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">          console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">          return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">        }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">        console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      default<\/span><span class=\"z-punctuation\">:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">        console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<p>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0437\u0430\u043c\u0435\u0442\u043d\u044b: \u043e\u0431\u0449\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u043c\u0430\u043d\u0434 \u043e\u043f\u0446\u0438\u0438 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438, \u043d\u043e \u0441\u0430\u043c\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u0438\u0441\u043f\u0430\u0442\u0447\u0438\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e. \u041d\u043e \u044d\u0442\u043e \u043b\u0435\u0433\u043a\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0443\u0440\u043e\u0432\u043d\u0435\u043c \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438!<\/p>\n<h2 id=\"uroven-2-prototipy-perechislenie-metodov\"><a class=\"anchor\" href=\"#uroven-2-prototipy-perechislenie-metodov\" title=\"link to section\">#<\/a>\u0423\u0440\u043e\u0432\u0435\u043d\u044c 2: \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u044b, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/h2>\n<p>\u0420\u0430\u0441\u0448\u0438\u0440\u0438\u043c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f <code>Program<\/code>: \u0432\u0441\u0435 \u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u044b \u0431\u0443\u0434\u0443\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044c\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 JS \u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0435\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0430, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u2014 \u044d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041f\u0440\u043e\u0442\u043e\u0442\u0438\u043f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043a\u043b\u0430\u0441\u0441\u0430 <code>A<\/code> \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043a\u0430\u043a <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Function\/prototype\"><code>A.prototype<\/code><\/a>.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0435 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u043e\u0432 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u043c\u0435\u0442\u043e\u0434\u044b <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Functions\/Method_definitions#method_definitions_in_classes\">\u043e\u0431\u044a\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0435-\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f\u0435\u043c\u044b\u043c\u0438<\/a>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c <code>Object.keys(Program.prototype)<\/code> \u0438\u043b\u0438 <code>for (k in Program.prototype)<\/code> \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f. \u041d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/getOwnPropertyNames\"><code>Object.getOwnPropertyNames()<\/code><\/a>, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439 <em>\u0432\u0441\u0435<\/em> \u043a\u043b\u044e\u0447\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430.<\/p>\n<p>\u0423 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u043d\u0430 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 <code>Object.keys()<\/code>. \u041d\u0430 \u043d\u0435\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 <code>Own<\/code> \u0432 \u0438\u043c\u0435\u043d\u0438 \u2014 \u043e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043b\u044e\u0447\u0438, \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0430\u0449\u0438\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u044d\u0442\u043e\u043c\u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u0443, <em>\u043d\u0435<\/em> \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u044f\u0441\u044c \u043f\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u043e\u0432 \u2014 \u0442\u043e \u0435\u0441\u0442\u044c, \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u044e\u0447\u0438. \u0415\u0441\u043b\u0438 \u043e\u043d\u0438 \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u043d\u0443\u0436\u043d\u044b, \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u043f\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u043e\u0432 \u0441\u0430\u043c\u0438\u043c \u2014 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> allKeys<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> proto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-support z-class\"> A<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> proto<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> proto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getPrototypeOf<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">proto<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  allKeys<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-keyword z-operator\">...<\/span><span class=\"z-source\">Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">proto<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0430\u0441\u0441\u0430 <code>Program<\/code>, \u043d\u0435 \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 \u043f\u0440\u0435\u0434\u043a\u043e\u0432. \u0422\u0430\u043a \u043d\u0430\u043c, \u043a \u0442\u043e\u043c\u0443 \u0436\u0435, \u043d\u0435 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0438\u0442\u0441\u044f \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u0430\u043a \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u0449\u0435\u0433\u043e \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u0440\u0435\u0434\u043a\u0430 <code>Object<\/code>.<\/p>\n<p>\u0412\u0430\u0436\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e <code>constructor<\/code> \u2014 \u044d\u0442\u043e \u0442\u043e\u0436\u0435 \u043a\u043b\u044e\u0447 \u0432 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430. \u0415\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<details><summary>stage2\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> sharedOpts<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> sharedOpts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u043e \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044e, \u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b `program` - \u044d\u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u044b<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0435 enumerable<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u0430 getOwnPropertyNames(), \u0430 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e keys()<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">filter<\/span><span class=\"z-source\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    (<\/span><span class=\"z-variable z-parameter\">k<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">function<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">constructor<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  )<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u043e\u0436\u0435\u043c \u0443\u0431\u0440\u0430\u0442\u044c \u0438\u0437 <code>main.ts<\/code> \u043a\u043e\u0434 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434:<\/p>\n<details><summary>stage2\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  v<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">v<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">name<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> args<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">command required 1 argument, 0 given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"uroven-3-argumenty-funktsii\"><a class=\"anchor\" href=\"#uroven-3-argumenty-funktsii\" title=\"link to section\">#<\/a>\u0423\u0440\u043e\u0432\u0435\u043d\u044c 3: \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0439<\/h2>\n<p>\u0425\u043e\u0440\u043e\u0448\u043e \u0431\u044b \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043c\u0430\u0441\u0441\u0438\u0432 <code>args<\/code> \u0441\u0430\u043c\u0438\u043c, \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441\u0430\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0447\u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441\u0430\u043c\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432-\u043a\u043e\u043c\u0430\u043d\u0434: \u0431\u0443\u0434\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u043d\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u043c, \u0430 \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u043c\u0435\u0442\u043e\u0434\u0430, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0432 <code>opts<\/code> \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u0435 \u043c\u0435\u0441\u0442\u043e:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0411\u044b\u043b\u043e:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">hello<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">string<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">Record<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-variable z-other z-readwrite\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">: <\/span><span class=\"z-keyword z-operator\">...<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0421\u0442\u0430\u043b\u043e:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">hello<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">Record<\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-variable z-other z-readwrite\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> name<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">string<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">: <\/span><span class=\"z-keyword z-operator\">...<\/span><\/span><\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0445 CLI-\u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0415\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043b\u044f \u043b\u044e\u0431\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>f<\/code> \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Function\/length\">\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>f.length<\/code><\/a>.<\/p>\n<p>\u041d\u043e \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0430 \u0445\u0438\u0442\u0440\u043e\u0441\u0442\u044c. \u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>f.length<\/code> \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0431\u0443\u0434\u0435\u0442 <em>\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c<\/em> \u0447\u0438\u0441\u043b\u043e\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438! \u041e\u043d\u043e \u043d\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u0443\u0447\u0430\u0438 \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> f1<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">a<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> b<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">assert<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">f1<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> rest-\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> f2<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">a<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-parameter\">bs<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">assert<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">f2<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e arguments<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> f3<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">a<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  doWork<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">arguments<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">2<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">assert<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">f3<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043f\u043b\u044e\u0441 \u043a \u044d\u0442\u043e\u043c\u0443, &quot;\u043b\u0438\u0448\u043d\u0438\u0435&quot; \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> f4<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">a<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">f4<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 3<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 4<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 5<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u044d\u0442\u043e, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<details><summary>stage3\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> rest-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> sharedOpts<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> sharedOpts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u043e \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044e, \u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b `program` - \u044d\u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u044b<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0435 enumerable<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u0430 getOwnPropertyNames(), \u0430 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e keys()<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">filter<\/span><span class=\"z-source\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    (<\/span><span class=\"z-variable z-parameter\">k<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">function<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">constructor<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  )<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u0443\u0435\u043c \u0447\u0438\u0441\u043b\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e, \u043c\u0435\u043d\u044c\u0448\u0435 \u043d\u0435\u0442<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> +1 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u0441 \u043e\u043f\u0446\u0438\u044f\u043c\u0438<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<details><summary>stage3\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  v<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">v<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"uroven-4-dekoratory-i-reflect-metadata\"><a class=\"anchor\" href=\"#uroven-4-dekoratory-i-reflect-metadata\" title=\"link to section\">#<\/a>\u0423\u0440\u043e\u0432\u0435\u043d\u044c 4: \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u044b \u0438 Reflect.metadata<\/h2>\n<p>\u0427\u0442\u043e\u0431\u044b \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0443\u043c\u0435\u043b \u0441\u0430\u043c \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u043a\u0430\u043a\u043e\u0435 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0435 \u0438\u043c\u044f \u0435\u0441\u0442\u044c \u0443 \u043e\u043f\u0446\u0438\u0438, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u0432\u0435\u0441\u0438\u0442\u044c \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0438 \u044d\u0442\u043e \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0435 \u0438\u043c\u044f, \u0438 \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0435\u0441\u043b\u0438 \u0431\u0443\u0434\u0435\u043c \u044f\u0432\u043d\u043e \u043e\u0442\u043c\u0435\u0447\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b-\u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430-\u043e\u043f\u0446\u0438\u0438, \u0442\u043e \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u043c\u0435\u0442\u044c \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>Program<\/code> \u0438 \u043f\u043e\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u043c\u0435\u0442\u043e\u0434\u044b.<\/p>\n<p>\u041f\u0440\u043e\u0449\u0435 \u0438 \u043a\u0440\u0430\u0441\u0438\u0432\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u044b.<\/p>\n<p>\u0423 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/tc39\/proposal-decorators\">\u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u043e\u0432<\/a> \u0432 JS \u0438 TS \u0442\u044f\u0436\u0435\u043b\u0430\u044f \u0441\u0443\u0434\u044c\u0431\u0430. \u041f\u0440\u043e\u043f\u043e\u0437\u0430\u043b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u044b\u0432\u0430\u043b\u0438, \u0438 \u043c\u043d\u043e\u0433\u0438\u0435 \u043a\u043e\u0434\u043e\u0432\u044b\u0435 \u0431\u0430\u0437\u044b \u0432\u0441\u0435 \u0435\u0449\u0435 \u0437\u0430\u0432\u044f\u0437\u0430\u043d\u044b \u043d\u0430 \u043f\u043e\u043b\u0438\u0444\u0438\u043b\u043b\u044b \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0445 \u0434\u0440\u0430\u0444\u0442\u043e\u0432 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0412 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0435 TypeScript \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u043e\u0432:<\/p>\n<ul>\n<li>\u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439; \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043e\u043f\u0446\u0438\u0439 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-0\/#decorators\">\u043d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 TypeScript 5.0<\/a><\/li>\n<li>\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a\u043e\u0432; \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/decorators.html\">\u0441 \u043e\u043f\u0446\u0438\u0435\u0439 <code>experimentalDecorators<\/code><\/a><\/li>\n<\/ul>\n<p>\u0417\u0430\u0431\u0435\u0433\u0430\u044f \u0432\u043f\u0435\u0440\u0435\u0434, \u0441\u043a\u0430\u0436\u0443, \u0447\u0442\u043e \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0445 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438 \u0432 TS \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e <code>experimentalDecorators<\/code>. \u041d\u043e \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0431\u043e\u0440\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/reflect-metadata\"><code>reflect-metadata<\/code><\/a>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0442\u0435\u043f\u0435\u0440\u044c \u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0435 Reflect \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u043e\u0432\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Foo<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043c\u0435\u0442\u043e\u0434 Reflect.metadata() \u043c\u043e\u0436\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u0430<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-meta z-decorator\">Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">meta-key<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">value<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  f<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043d\u043e \u043b\u0443\u0447\u0448\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0435\u0433\u043e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> MyDecorator<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">value<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043b\u044e\u0447\u0430 \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0430\u043c\u0443 \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">MyDecorator<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> value<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Bar<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">MyDecorator<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">value<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0447\u0438\u0442\u0430\u0442\u044c \u0432\u043e\u0442 \u0442\u0430\u043a:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> value1<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Foo<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">meta-key<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">f<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> value2<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Bar<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> MyDecorator<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">prop<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0435\u0441\u043b\u0438 \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0432\u0435\u0440\u043d\u0443\u0442\u0441\u044f \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435, \u043d\u0430\u0432\u0435\u0448\u0435\u043d\u043d\u044b\u0435 \u043d\u0430 \u0441\u0430\u043c \u043a\u043b\u0430\u0441\u0441, \u0430 \u043d\u0435 \u043d\u0430 \u0435\u0433\u043e \u0447\u043b\u0435\u043d\u044b<\/span><\/span><\/code><\/pre>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u044b, <code>reflect-metadata<\/code> \u0438 \u043e\u0431\u0445\u043e\u0434 \u043a\u043b\u044e\u0447\u0435\u0439 \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0443\u0440\u043e\u0432\u043d\u0435\u0439, \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u0443\u044e \u0444\u0438\u0447\u0443:<\/p>\n<details><summary>stage4\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  short<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Reflect.metadata<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043b\u044e\u0447\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0434\u043e\u0431\u043d\u043e \u0431\u0440\u0430\u0442\u044c \u0441\u0430\u043c\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Option<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">def<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> def<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0439 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u0438 \u0443\u0434\u043e\u0431\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0433\u0435\u0442\u0442\u0435\u0440<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">    |<\/span><span class=\"z-variable z-other z-readwrite\"> OptionDefinition<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">    |<\/span><span class=\"z-constant z-language z-undefined z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0443 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u0430 \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0435\u0433\u043e \u0443\u0434\u043e\u0431\u043d\u043e \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Command<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043a\u043e\u0434 \u0432 <code>main.ts<\/code> \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<details><summary>stage4\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u043e\u043f\u0446\u0438\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0435 \u0438\u043c\u044f<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">v<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u043f\u043e\u043b\u044f, \u043d\u0435 \u044f\u0432\u043b\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u043e\u043f\u0446\u0438\u044f\u043c\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  version<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">1.0.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Command<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u043e\u043f\u0446\u0438\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0440\u0443\u043a\u0430\u043c\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"uroven-5-opisanie-tipov-dlia-rantaima\"><a class=\"anchor\" href=\"#uroven-5-opisanie-tipov-dlia-rantaima\" title=\"link to section\">#<\/a>\u0423\u0440\u043e\u0432\u0435\u043d\u044c 5: \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0438\u043f\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0430<\/h2>\n<p>\u041d\u0435\u043f\u043b\u043e\u0445\u043e \u0431\u044b \u0432 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 <code>@Option()<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a\u0436\u0435 \u0442\u0438\u043f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043e\u043f\u0446\u0438\u0438. \u041d\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0438\u043f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 JS \u0434\u0440\u0443\u0433\u0438\u043c JS-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c, \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043d\u0435\u0442. \u0415\u0441\u0442\u044c, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0442\u043e, \u0447\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>typeof<\/code>, \u043d\u043e \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u2014 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432.<\/p>\n<p>\u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0435\u0441\u0442\u044c \u0440\u044f\u0434 \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0438 \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438 \u0434\u043b\u044f \u0442\u0430\u043a\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438. \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u044f \u0431\u0443\u0434\u0443 \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.nestjs.com\/openapi\/types-and-parameters#arrays\">\u043f\u043e\u0432\u0441\u0435\u043c\u0435\u0441\u0442\u043d\u043e<\/a> <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.nestjs.com\/techniques\/mongodb#model-injection\">\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f<\/a> <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.nestjs.com\/\">\u0432 Nest.js<\/a>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0438\u0445 &quot;\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u043c&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> number<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> Number<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> string<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043c\u0430\u0441\u0441\u0438\u0432\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043e\u0434\u043d\u043e\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043d\u044b\u043c\u0438 \u043c\u0430\u0441\u0441\u0438\u0432\u0430\u043c\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> arrayOfNumber<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Number<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> arrayOfString<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b, \u043a\u0445\u043c, \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> person<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  name<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  age<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> Number<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0438 \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043b\u044e\u0431\u044b\u0445 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f\u0445<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> dto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  people<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> name<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> age<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> Number<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441, \u043f\u043e\u0445\u043e\u0436\u0438\u0439 \u043d\u0430 \u0442\u0438\u043f\u044b \u0432 TypeScript<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">type<\/span><span class=\"z-entity z-name z-type\"> Dto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  people<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-object z-property\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-object z-property\"> age<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0412 TypeScript \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0442\u0430\u043a\u0438\u043c \u0440\u0430\u043d\u0442\u0430\u0439\u043c-\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0442\u0438\u043f\u043e\u0432 \u0432\u0430\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c, \u0433\u0434\u0435 \u043e\u043d\u043e, \u0430 \u0433\u0434\u0435 \u0442\u0438\u043f\u044b \u0441\u0430\u043c\u043e\u0433\u043e TypeScript. \u0415\u0441\u043b\u0438, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u0435 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043a\u0430\u043a <code>Number<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>number<\/code>, \u0442\u043e \u043e\u0448\u0438\u0431\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0441\u043a\u043e\u0447\u0438\u0442\u044c \u0432 \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u2014 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/play#code\/DYUwLgBAhgXBByBXAtgIxAJwgXggRgCYBmAbgChRJU4A7FdLXAFgFYA2csqHCVc1HlBJA\">\u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0432\u043e\u0438\u0442\u044c<\/a> \u043a \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439, \u0442\u0438\u043f \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u2014 \u0435\u0433\u043e boxed-\u0432\u0435\u0440\u0441\u0438\u044f. \u041d\u043e \u043d\u0435 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442!<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u0430\u043a\u043e\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0434\u043b\u044f \u0442\u0438\u043f\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0430\u0448 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0442\u0438\u043f\u043e\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043e\u043f\u0446\u0438\u0439. \u041e\u0431\u043b\u0435\u0433\u0447\u0438\u0442 \u043d\u0430\u043c \u0437\u0430\u0434\u0430\u0447\u0443 \u0442\u043e, \u0447\u0442\u043e <code>parseArgs<\/code> \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442, \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0442\u044b\u0440\u0435 \u0442\u0438\u043f\u0430: <code>boolean | string | boolean[] | string[]<\/code>:<\/p>\n<details><summary>stage5\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> ParseArgsConfig<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  short<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0442\u0430\u043a\u043e\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0434\u043b\u044f \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435 \u0443\u0436\u0435 \u0441\u0442\u0430\u043b \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c \u0434\u0435-\u0444\u0430\u043a\u0442\u043e<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  type<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Option<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">def<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> def<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">    |<\/span><span class=\"z-variable z-other z-readwrite\"> OptionDefinition<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">    |<\/span><span class=\"z-constant z-language z-undefined z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Command<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u044d\u0442\u043e\u0442 \u0442\u0438\u043f \u043d\u0435 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043e\u0432\u0430\u0440\u0438\u043c\u043e\u043c \u0432\u0438\u0434\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">type<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Exclude<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">ParseArgsConfig<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">options<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> config<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">Array<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">isArray<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    config<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> config<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<details><summary>stage5\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> type<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">v<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  version<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">1.0.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Command<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"uroven-6-sprashivaem-tipy-u-samogo-typescript\"><a class=\"anchor\" href=\"#uroven-6-sprashivaem-tipy-u-samogo-typescript\" title=\"link to section\">#<\/a>\u0423\u0440\u043e\u0432\u0435\u043d\u044c 6: \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c \u0442\u0438\u043f\u044b \u0443 \u0441\u0430\u043c\u043e\u0433\u043e TypeScript<\/h2>\n<p>\u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 TypeScript, \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0435 \u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u044c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435 \u2014 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u044f \u0438\u0445 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0432 TypeScript \u2014 \u0430 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0443 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u0438\u043f\u0430\u0445 \u0432 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f:<\/p>\n<ul>\n<li>\u043e\u043f\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/tsconfig#emitDecoratorMetadata\"><code>emitDecoratorMetadata<\/code><\/a> \u2014 \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445<\/li>\n<li>\u043e\u043f\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/tsconfig#experimentalDecorators\"><code>experimentalDecorators<\/code><\/a> \u2014 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0435\u0440\u0432\u043e\u0439 \u043e\u043f\u0446\u0438\u0438<\/li>\n<li>\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/reflect-metadata\"><code>reflect-metadata<\/code><\/a> \u2014 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445<\/li>\n<\/ul>\n<p>\u041d\u0443\u0436\u043d\u044b \u0438\u043c\u0435\u043d\u043d\u043e \"\u0441\u0442\u0430\u0440\u044b\u0435\" \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u044b, \u0430 \u043d\u0435 \u043d\u043e\u0432\u044b\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u043c \u043c\u043e\u043c\u0435\u043d\u0442, <code>emitDecoratorMetadata<\/code> <em>\u0442\u0440\u0435\u0431\u0443\u0435\u0442<\/em> <code>experimentalDecorators<\/code>.<\/p>\n<p>\u041c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0447\u043b\u0435\u043d\u043e\u0432 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u043f\u0440\u0438\u0447\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0442\u0435\u0445, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0436\u0435 \u0432\u0438\u0441\u0438\u0442 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440. \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043d\u0435 \u043e\u043f\u0438\u0441\u0430\u043d \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430, \u043d\u043e \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u0435\u0441\u043b\u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/play?experimentalDecorators=true&amp;emitDecoratorMetadata=true&amp;target=9#code\/CYUwxgNghgTiAEYD2A7AzgF3gWQJ4BFwkYoNiAueAMQFcUwMBLVAbgCg3Io01qkl4AbzbxR8AAJ5CyEmRgixoGaRDAACjCQAHAISVMMRigDm7BaLpLiK9Zt36Mhk2bESpRWcXPwrs1dhAMAAskYAAKADN+Sip+ABp4FEoUGgBbACMQGABKBydjIW9XOAwaGBR4ACJuYAjK9lcAXzZGoA\">\u043f\u043e\u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c<\/a> \u0441 \u0442\u0435\u043c, \u0432\u043e \u0447\u0442\u043e \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0421\u0430\u043c\u043e\u0435 \u0432\u0430\u0436\u043d\u043e\u0435, \u0447\u0442\u043e \u043e \u043d\u0435\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u2014 \u043e\u043d \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439, \u043a\u0430\u043a \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b. \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0433\u043e \"\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\", \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u043f\u043e\u043d\u044f\u0442\u0438\u0435 \u043a \u043d\u0435\u043c\u0443 \u0432\u043e\u043e\u0431\u0449\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u043e. \u0422\u043e \u0435\u0441\u0442\u044c, \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430 <code>Foo<\/code> \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d <code>Foo<\/code>, \u0434\u043b\u044f <code>number<\/code> \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d <code>Number<\/code>, \u0434\u043b\u044f <code>number[]<\/code> \u2014 <code>Array<\/code>, \u0430 \u0434\u043b\u044f \u0442\u0438\u043f\u0430-\u043b\u0438\u0442\u0435\u0440\u0430\u043b\u0430 <code>{ name: string }<\/code> \u2014 \u043f\u0440\u043e\u0441\u0442\u043e <code>Object<\/code>. \u041e\u0431\u0438\u0434\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u0437\u0430 \u043c\u0430\u0441\u0441\u0438\u0432\u044b: \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0445\u043e\u0442\u044f \u0431\u044b \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u043d\u043e \u0434\u043b\u044f \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432 \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u044f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0442\u0438\u043f \u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<p>\u0418\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0440\u0430\u0434\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0435\u0437 TypeScript, \u044d\u0442\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u0438\u043f\u0430\u0445 \u043d\u0435\u043b\u044c\u0437\u044f \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439. \u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e, \u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0442\u0430\u0432\u0442\u043e\u043b\u043e\u0433\u0438\u0438 \u043e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c.<\/p>\n<details><summary>stage6\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> ParseArgsConfig<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  short<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  type<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Option<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">def<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> def<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">    |<\/span><span class=\"z-variable z-other z-readwrite\"> OptionDefinition<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">    |<\/span><span class=\"z-constant z-language z-undefined z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Command<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">type<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Exclude<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">ParseArgsConfig<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">options<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> config<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438\u0437 \u0442\u0438\u043f\u043e\u0432 TypeScript<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> defType<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">design:type<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">Array<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">isArray<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      throw<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unable to determine option type for <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    config<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> config<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<details><summary>stage6\/main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> OptionValue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0434\u043b\u044f \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b emitDecoratorMetadata<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u044f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u0438\u043f\u044b, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0432\u0435\u0441\u0442\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">v<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  version<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">1.0.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Command<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">enthusiastic<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> opts<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">e<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-keyword z-operator\"> !==<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">invalid type for --enthusiastic option<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"uroven-7-tipy-argumentov-metodov-dto-klassy\"><a class=\"anchor\" href=\"#uroven-7-tipy-argumentov-metodov-dto-klassy\" title=\"link to section\">#<\/a>\u0423\u0440\u043e\u0432\u0435\u043d\u044c 7: \u0442\u0438\u043f\u044b \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, DTO-\u043a\u043b\u0430\u0441\u0441\u044b<\/h2>\n<p>\u0422\u0435\u043c \u0436\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u2014 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>emitDecoratorMetadata<\/code> \u2014 \u043c\u043e\u0436\u043d\u043e \u0443\u0437\u043d\u0430\u0442\u044c \u0438 \u0442\u0438\u043f\u044b \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u044d\u0442\u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u043a\u043e\u043d\u0435\u0446-\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0443 \u0441\u0430\u043c\u043e\u043c\u0443 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0442\u0438\u043f\u044b \u043e\u043f\u0446\u0438\u0439 \u0434\u043b\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434.<\/p>\n<p>\u041f\u043e\u0434\u0432\u043e\u0445, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u2014 \u043a\u0430\u043a \u044f \u043f\u0438\u0441\u0430\u043b \u0432\u044b\u0448\u0435 \u2014 \u0434\u043b\u044f \u0442\u0438\u043f\u043e\u0432-\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f, \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u0442\u0438\u043f \u2014 \u043a\u043b\u0430\u0441\u0441. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043e\u0439\u0442\u0438 \u044d\u0442\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435, \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u0442\u0438\u043f\u044b-\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438\u043c\u0435\u043d\u043d\u043e \u043a\u0430\u043a <code>class<\/code>, \u0430 \u043d\u0435 \u043a\u0430\u043a <code>interface<\/code> \u0438\u043b\u0438 \u0442\u0438\u043f-\u043b\u0438\u0442\u0435\u0440\u0430\u043b.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0432\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">interface<\/span><span class=\"z-entity z-name z-type\"> IOptions<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  enthusiastic<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u0442\u0430\u043a:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Options<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  enthusiastic<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0442\u0438\u043f\u043e\u0432 \u0442\u0430\u043a\u043e\u0435 \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts1<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Options<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-source\"> enthusiastic<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts2<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Options<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-constant\"> JSON<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">parse<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">str<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043d\u0435 \u0441\u0442\u0430\u043d\u0443\u0442 \u0432\u043e\u043b\u0448\u0435\u0431\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430 Options<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">assert<\/span><span class=\"z-source\">(<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">opts1<\/span><span class=\"z-keyword z-operator z-expression z-instanceof z-ts\"> instanceof<\/span><span class=\"z-entity z-name z-type\"> Options<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u044d\u0442\u043e\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0448\u0442\u0440\u0438\u0445 \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0443, \u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u043c\u0443 \u043a\u043e\u0434\u0443 \u0443\u0436\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u043f\u0446\u0438\u0438 \u0440\u0443\u043a\u0430\u043c\u0438:<\/p>\n<details><summary>stage7\/framework.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">reflect-metadata<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> ParseArgsConfig<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  short<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  type<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\"> typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-meta z-type\"> [<\/span><span class=\"z-keyword z-operator z-expression z-typeof z-ts\">typeof<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Option<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">def<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionDefinition<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> def<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">    |<\/span><span class=\"z-variable z-other z-readwrite\"> OptionDefinition<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">    |<\/span><span class=\"z-constant z-language z-undefined z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> const<\/span><span class=\"z-entity z-name z-function\"> Command<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">metadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">ctor<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> prop<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> ctor<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> prop<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> CommandFn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-meta z-type\"> (<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  ...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-meta z-type\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">  |<\/span><span class=\"z-entity z-name z-type\"> Array<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">boolean<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> program<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Program<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-variable z-other z-constant z-ts\">command<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> commands<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getOwnPropertyNames<\/span><span class=\"z-source\">(<\/span><span class=\"z-support z-class\">Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getCommandMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">no command specified<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">includes<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unknown command: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">available commands: <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">commands<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">join<\/span><span class=\"z-string\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> OptsDto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">design:paramtypes<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-support z-class\">    Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    command<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  )<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> optsDto<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> OptsDto<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> OptsDto<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-constant z-language z-undefined z-ts\"> undefined<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    positionals<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-constant z-ts\">args<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    values<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-ts\"> opts<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      ...<\/span><span class=\"z-entity z-name z-function\">getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      ...<\/span><span class=\"z-entity z-name z-function\">getOptionsConfigFromMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">OptsDto<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> optsDto<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">assign<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">optsDto<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-entity z-name z-function\"> commandFn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Function<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> minArgCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> commandFn<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-variable z-other z-readwrite\"> minArgCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">too few arguments for command <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">at least <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">minArgCount<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">, <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-string\">length<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> given<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> code<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-other z-readwrite\"> program<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">command<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">optsDto<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> ...<\/span><span class=\"z-variable z-other z-readwrite\">args<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> code<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> catch<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">exitCode<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    throw<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">type<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-type\"> Exclude<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">ParseArgsConfig<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">options<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-type z-builtin z-ts\"> undefined<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> getOptionsConfigFromMetadata<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  Program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  program<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-ts\"> config<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> OptionsConfig<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">program<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438\u0437 \u0442\u0438\u043f\u043e\u0432 TypeScript<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> defType<\/span><span class=\"z-keyword z-operator\"> =<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">type<\/span><span class=\"z-keyword z-operator\"> ??<\/span><span class=\"z-source\"> Reflect<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">getMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">design:type<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-support z-class\"> Program<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">prototype<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">Array<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">isArray<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      multiple<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> String<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-keyword\"> if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">defType<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> ===<\/span><span class=\"z-variable z-other z-readwrite\"> Boolean<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        type<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">boolean<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-keyword\"> else<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      throw<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Error<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">unable to determine option type for <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    config<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> short<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> type<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> multiple<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> config<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> extractOptions<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  Dto<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-keyword\"> new<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type z-function z-arrow z-ts\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  dto<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  opts<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Record<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-type\"> OptionValue<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> k<\/span><span class=\"z-keyword z-operator z-expression z-of z-ts\"> of<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">keys<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">dto<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-ts\"> def<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> getOptionMetadata<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Dto<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> k<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">def<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> continue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator\"> &amp;&amp;<\/span><span class=\"z-source\"> def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      dto<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-source\">def<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">short<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-keyword z-operator z-expression z-in z-ts\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      dto<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">      delete<\/span><span class=\"z-variable z-other z-readwrite\"> opts<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">k<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0439 \u043a\u043e\u0434 \u0438\u0437 <code>main.ts<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Command<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> Option<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> run<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/framework.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043c\u043e\u0436\u043d\u043e \u0434\u0430\u0436\u0435 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043a\u0430\u043a abstract<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> HelloOptions<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">e<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  enthusiastic<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Program<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Option<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-meta z-decorator\"> short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">v<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  verbose<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> boolean<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  version<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">1.0.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-decorator z-ts\">  @<\/span><span class=\"z-entity z-name z-function\">Command<\/span><span class=\"z-meta z-decorator\">(<\/span><span class=\"z-meta z-decorator\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  hello<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-parameter\"> enthusiastic<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> HelloOptions<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> name<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">verbose<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">debug<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-other z-readwrite\"> enthusiastic<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-string\">Hello <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">name<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-variable z-other z-readwrite\">enthusiastic<\/span><span class=\"z-keyword z-operator\"> ?<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">!<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-keyword z-operator\"> :<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> run<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">Program<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><h2 id=\"conclusion\"><a class=\"anchor\" href=\"#conclusion\" title=\"link to section\">#<\/a>@Conclusion()<\/h2>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0438\u0437 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u043d\u0430\u043c \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u043f\u0440\u044f\u0442\u0430\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0432\u0435\u0441\u044c \u043a\u043e\u0434, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0439 \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438. \u041a\u043b\u0438\u0435\u043d\u0442\u0443 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043a\u043e\u0434 \u0432 \u043a\u043b\u0430\u0441\u0441\u044b, \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044f\u0441\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0439, \u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0443\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u0432\u0441\u0435 \u0441\u0430\u043c.<\/p>\n<p>\u0421\u0445\u043e\u0436\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0448\u0438\u0440\u043e\u043a\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432\u043e \u043c\u043d\u043e\u0433\u0438\u0445 TypeScript-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u0445. \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0432\u0434\u043e\u0445\u043d\u043e\u0432\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u0431\u044b\u043b, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.nestjs.com\/\">Nest.js<\/a>. \u041d\u043e \u044f \u0441\u0447\u0438\u0442\u0430\u044e, \u0447\u0442\u043e \u2014 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0432\u044b\u0431\u043e\u0440\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u2014 \u0437\u043d\u0430\u043d\u0438\u0435 \u044d\u0442\u0438\u0445 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0435, \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u044b\u0435 \u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u0435 API.<\/p>\n"},{"title":"(\u041f\u0435\u0440\u0435\u0432\u043e\u0434) \u041a\u0430\u043a \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u043b\u0438 \u0440\u0430\u0437\u043c\u0435\u0440 VS Code, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f name mangling","published":"2023-08-22T00:00:00+00:00","updated":"2023-08-22T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/translations\/vscode-name-mangling\/"}},"id":"https:\/\/iliazeus.lol\/translations\/vscode-name-mangling\/","content":"<p>\u041d\u0435 \u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e, \u043c\u044b \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b\u0438 \u043d\u0430 20% \u043e\u0431\u044a\u0435\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e JavaScript-\u043a\u043e\u0434\u0430 \u0432 Visual Studio Code. \u0412 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u0445 \u0447\u0438\u0441\u043b\u0430\u0445 \u044d\u0442\u043e \u043e\u043a\u043e\u043b\u043e 3.9 \u041c\u0411. \u0425\u043e\u0442\u044c \u044d\u0442\u043e \u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u0442\u0438\u043f\u0438\u0447\u043d\u043e\u0439 \u0433\u0438\u0444\u043a\u0438 \u0438\u0437 \u0431\u043b\u043e\u0433\u0430, \u0446\u0438\u0444\u0440\u0430 \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f! \u042d\u0442\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043e\u0431\u044a\u0435\u043c \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f, \u043d\u043e \u0438 \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430: \u043c\u0435\u043d\u044c\u0448\u0435 \u043a\u043e\u0434\u0430 \u0437\u043d\u0430\u0447\u0438\u0442 \u043c\u0435\u043d\u044c\u0448\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0435\u0440\u0430 \u0438 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0442\u043e\u0440\u0430. \u0418 \u043a\u043e \u0432\u0441\u0435\u043c\u0443 \u043f\u0440\u043e\u0447\u0435\u043c\u0443, \u043c\u044b \u0434\u043e\u0431\u0438\u043b\u0438\u0441\u044c \u044d\u0442\u043e\u0433\u043e \u0431\u0435\u0437 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0438\u043b\u0438 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u043e\u0432. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e, \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u043d\u0430\u0434 \u043d\u043e\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u0441\u0431\u043e\u0440\u043a\u0438: name mangling, \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u043d \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u0430\u043a \u043c\u044b \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u0430\u043a\u0438\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u043b\u0438, \u0438 \u043a\u0430\u043a \u0432 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432 \u0434\u043e\u0431\u0438\u043b\u0438\u0441\u044c \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043d\u0430 20%. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u0442\u0430\u043a \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u0438\u043a\u0438 \u2014 \u044f \u0445\u043e\u0447\u0443, \u0441\u043a\u043e\u0440\u0435\u0435, \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 VS Code \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0442 \u043a \u0440\u0435\u0448\u0435\u043d\u0438\u044e \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u0422\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0447\u0442\u043e \u043d\u0430\u0448\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435, \u0438 \u0443\u0436 \u0442\u043e\u0447\u043d\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 \u043d\u0435 \u0432\u0441\u0435\u043c \u043a\u043e\u0434\u043e\u0432\u044b\u043c \u0431\u0430\u0437\u0430\u043c.<\/p>\n<h2 id=\"diagnostiruem-problemu\">\u0414\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443<\/h2>\n<p>\u041a\u043e\u043c\u0430\u043d\u0434\u0430 VS Code \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043a \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u041c\u044b \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0433\u043e\u0440\u044f\u0447\u0438\u0439 \u043a\u043e\u0434, \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u043e\u043a UI \u0438 \u0443\u0441\u043a\u043e\u0440\u044f\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u041a\u0440\u043e\u043c\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0447\u0435\u0433\u043e, \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0415\u0449\u0435 \u0431\u043e\u043b\u0435\u0435 \u043d\u0430\u0441\u0443\u0449\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0441\u0442\u0430\u043b\u0430 \u0441 \u0432\u044b\u0445\u043e\u0434\u043e\u043c web-\u0432\u0435\u0440\u0441\u0438\u0438 VS Code (https:\/\/vscode.dev). \u041f\u043e \u044d\u0442\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c, \u043c\u044b \u0441\u043b\u0435\u0434\u0438\u043c \u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043e\u0442 \u0440\u0435\u043b\u0438\u0437\u0430 \u043a \u0440\u0435\u043b\u0438\u0437\u0443.<\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440 \u0440\u0430\u0441\u0442\u0435\u0442. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0441\u0442\u0430\u0440\u0430\u0435\u043c\u0441\u044f \u043d\u0435 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0436\u0430\u0442\u044c VS Code \u0444\u0438\u0447\u0430\u043c\u0438, \u043e\u0442\u0434\u0430\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043d\u0430 \u043e\u0442\u043a\u0443\u043f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c, \u0438\u0445 \u0447\u0438\u0441\u043b\u043e \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f, \u0430 \u0441 \u043d\u0438\u043c\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0438 \u043d\u043e\u0432\u044b\u0439 \u043a\u043e\u0434. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>workbench.js<\/code>, \u043e\u0434\u0438\u043d \u0438\u0437 \u043d\u0430\u0448\u0438\u0445 \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u0437\u0430 \u0432\u043e\u0441\u0435\u043c\u044c \u043b\u0435\u0442 \u0432\u044b\u0440\u043e\u0441 \u0432 \u0447\u0435\u0442\u044b\u0440\u0435 \u0440\u0430\u0437\u0430. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u044d\u0442\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u0442\u043e\u0433\u0434\u0430 \u0443 VS Code, \u0435\u0449\u0435 \u043d\u0435 \u0431\u044b\u043b\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0445 \u0441\u0435\u0439\u0447\u0430\u0441 \u0444\u0438\u0447 \u2014 \u0432\u043a\u043b\u0430\u0434\u043e\u043a, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0438\u043b\u0438 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430. \u041d\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043a\u043e\u0434\u0430 \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043d\u0430\u0441 \u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0438\u043b\u043e.<\/p>\n<figure class=\"border\">\n<p><img src=\"https:\/\/iliazeus.lol\/translations\/vscode-name-mangling\/graph.png\" alt=\"\u0420\u0430\u0437\u043c\u0435\u0440 workbench.js, \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 VS Code, \u043f\u043e \u0432\u0435\u0440\u0441\u0438\u044f\u043c\" \/><\/p>\n<figcaption>\u0420\u0430\u0437\u043c\u0435\u0440 workbench.js, \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 VS Code, \u043f\u043e \u0432\u0435\u0440\u0441\u0438\u044f\u043c<\/figcaption>\n<\/figure>\n<p>\u0420\u0430\u0437\u043c\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0433 \u0431\u044b \u0432\u044b\u0440\u0430\u0441\u0442\u0438 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u0432 \u0447\u0435\u0442\u044b\u0440\u0435 \u0440\u0430\u0437\u0430 \u2014 \u0435\u0441\u043b\u0438 \u0431\u044b \u043c\u044b \u0432\u0441\u0435 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0435 \u0438\u0441\u043a\u0430\u043b\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0441 \u044d\u0442\u0438\u043c \u0431\u043e\u0440\u043e\u0442\u044c\u0441\u044f. \u0412\u0441\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u044b \u0443\u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c; \u0432 \u0438\u0445 \u0447\u0438\u0441\u043b\u0435 \u043c\u0438\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/esbuild.github.io\/\">esbuild<\/a>. \u0410 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0441 \u0433\u043e\u0434\u0430\u043c\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0432\u0441\u0435 \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u041c\u043d\u043e\u0433\u0438\u0435 \u0438\u0437 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0439 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0440\u0438\u0441\u043a\u043e\u0432\u0430\u043d\u043d\u044b, \u0438\u043b\u0438 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u043e-\u0447\u0430\u0441\u043e\u0432 \u0434\u043b\u044f \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0433\u043e\u0434\u044b \u0448\u043b\u0438, \u0430 \u0440\u0430\u0437\u043c\u0435\u0440 \u0431\u0438\u043b\u0434\u0430 \u0440\u043e\u0441.<\/p>\n<p>\u041f\u043e\u043a\u0430 \u043e\u0434\u043d\u0430\u0436\u0434\u044b, \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u043c \u0433\u043e\u0434\u0443, \u044f \u043d\u0435 \u0437\u0430\u043c\u0435\u0442\u0438\u043b \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u0443\u044e \u0432\u0435\u0449\u044c. \u041d\u0430\u0448 \u043c\u0438\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 JavaScript-\u043a\u043e\u0434 \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043a\u0443\u0447\u0443 \u0434\u043b\u0438\u043d\u043d\u044b\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0432\u0440\u043e\u0434\u0435 <code>extensionIgnoredRecommendationsService<\/code>. \u041d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u043e \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e <code>esbuild<\/code> \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u043b \u0443\u043c\u0435\u0442\u044c \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0438\u0445 \u0432 \u0431\u043e\u043b\u0435\u0435 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435!<\/p>\n<p>\u042d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432 \u0441\u0440\u0435\u0434\u0435 JavaScript-\u0442\u0443\u043b\u0438\u043d\u0433\u0430 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 name mangling \u2014 \u0442\u0435\u0440\u043c\u0438\u043d <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/en.wikipedia.org\/wiki\/Name_mangling\">\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043d<\/a> \u0438\u0437 \u043c\u0438\u0440\u0430 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432, \u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0438. \u041a\u0430\u043a \u0447\u0430\u0441\u0442\u044c \u043c\u0438\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 JavaScript, name mangling \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u043b\u0438\u043d\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430 \u0432 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> someLongVariableName<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 123<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">someLongVariableName<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u041f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u0430\u043a\u043e\u0439:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> x<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 123<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">x<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0421 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u044f\u0437\u044b\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432 \u043c\u0430\u0448\u0438\u043d\u043d\u044b\u0439 \u043a\u043e\u0434, \u0442\u0430\u043a\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0433\u043b\u0443\u043f\u043e. \u041d\u043e \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 TypeScript \u0438 JavaScript \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 JS-\u043a\u043e\u0434\u0430, \u0434\u043b\u0438\u043d\u0430 \u0438\u043c\u0435\u043d \u0438\u0433\u0440\u0430\u0435\u0442 \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u0440\u043e\u043b\u044c \u0432 \u0440\u0430\u0437\u043c\u0435\u0440\u0435 \u0431\u0438\u043b\u0434\u0430.<\/p>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u043d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u0431\u0440\u043e\u0441\u0430\u0442\u044c \u0432\u0441\u0435 \u0438 \u0438\u0434\u0442\u0438 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432 \u043a\u043e\u0434\u0435. \u0414\u0430\u0436\u0435 \u0441\u0430\u043c\u044b\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0431\u0438\u043b\u0434\u0430 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0434\u0442\u0438 \u0432 \u0443\u0449\u0435\u0440\u0431 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u0434\u0430 \u2014 \u0430 \u043a\u043e\u0434, \u0433\u0434\u0435 \u0432\u0441\u0435 \u0438\u043c\u0435\u043d\u0430 \u043e\u0434\u043d\u043e\u0431\u0443\u043a\u0432\u0435\u043d\u043d\u044b\u0435, \u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c! \u0414\u0440\u0443\u0433\u043e\u0435 \u0434\u0435\u043b\u043e \u2014 \u043c\u0435\u043d\u044f\u0442\u044c \u0438\u043c\u0435\u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u0430\u043a \u044d\u0442\u043e \u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0434\u0435\u043b\u0430\u0442\u044c <code>esbuild<\/code>.<\/p>\n<p>\u041f\u0440\u0430\u0432\u0434\u0430, \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442, \u043e\u0447\u0435\u043d\u044c \u043a\u043e\u043d\u0441\u0435\u0440\u0432\u0430\u0442\u0438\u0432\u0435\u043d. \u041e\u043d \u043c\u0435\u043d\u044f\u0435\u0442 \u0438\u043c\u0435\u043d\u0430, \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0442\u043e\u0447\u043d\u043e \u0443\u0432\u0435\u0440\u0435\u043d, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0441\u043b\u043e\u043c\u0430\u0435\u0442; \u0433\u0440\u0443\u0431\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u043e\u043d \u043c\u0435\u043d\u044f\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043c\u0435\u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0439. \u0422\u0430\u043a\u043e\u0435 \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u0435 \u0432\u043f\u043e\u043b\u043d\u0435 \u0440\u0430\u0437\u0443\u043c\u043d\u043e \u2014 \u0434\u0435\u0431\u0430\u0436\u0438\u0442\u044c \u043a\u043e\u0434, \u0441\u043b\u043e\u043c\u0430\u043d\u043d\u044b\u0439 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043c\u0438\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u044d\u0442\u043e \u0442\u043e \u0435\u0449\u0435 \u0440\u0430\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435. \u041d\u043e, \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043c\u043d\u043e\u0433\u0438\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b <code>esbuild<\/code> \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442, \u0445\u043e\u0442\u044f \u043c\u043e\u0433 \u0431\u044b \u0438\u0445 \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c.<\/p>\n<p>\u041a\u0430\u043a \u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a name mangling \u043c\u043e\u0436\u0435\u0442 \u0432\u0441\u0435 \u0441\u043b\u043e\u043c\u0430\u0442\u044c, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> obj<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-source\"> longPropertyName<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-numeric\"> 123<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> lookup<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">prop<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> obj<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">prop<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-entity z-name z-function\">lookup<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">longPropertyName<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u041c\u0438\u043d\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043c\u043e\u0433 \u0431\u044b \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c <code>longPropertyName<\/code> \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e <code>x<\/code>. \u041d\u043e \u0442\u043e\u0433\u0434\u0430 \u0431\u044b \u0441\u043b\u043e\u043c\u0430\u043b\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u043e\u043b\u044e \u043f\u043e \u043a\u043b\u044e\u0447\u0443-\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> obj<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-source\"> x<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-numeric\"> 123<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> \u0417\u0434\u0435\u0441\u044c \u043c\u0438\u043d\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u043c\u0435\u043d\u0438\u043b `longPropertyName`<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">function<\/span><span class=\"z-entity z-name z-function\"> lookup<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">prop<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> obj<\/span><span class=\"z-source\">[<\/span><span class=\"z-variable z-other z-readwrite\">prop<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-entity z-name z-function\">lookup<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">longPropertyName<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> \u0410 \u0437\u0434\u0435\u0441\u044c \u2014 \u043d\u0435\u0442, \u0438 \u0432\u0441\u0435 \u0441\u043b\u043e\u043c\u0430\u043b\u043e\u0441\u044c<\/span><\/span><\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0435 \u0434\u0435\u043b\u043e, \u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439. \u041d\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d-\u043a\u043e\u0434\u0435. \u0421\u043b\u043e\u043c\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0433\u0443\u0442:<\/p>\n<ul>\n<li>\u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u043e\u043b\u044e \u043f\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439;<\/li>\n<li>\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433 JSON;<\/li>\n<li>API, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0430\u0448 \u043a\u043e\u0434 \u2014 \u043a\u043b\u0438\u0435\u043d\u0442 \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430;<\/li>\n<li>API, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0432\u044b \u2014 \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, DOM.<\/li>\n<\/ul>\n<p>\u041d\u0435\u0441\u043e\u043c\u043d\u0435\u043d\u043d\u043e, <code>esbuild<\/code> \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043e\u043e\u0431\u0449\u0435 \u0432\u0441\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b. \u041d\u043e \u0441\u0440\u0430\u0437\u0443 \u0441\u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u0435 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u044b\u0448\u0435 \u2014 \u0438 \u0434\u043b\u044f VS Code \u044d\u0442\u043e \u0444\u0430\u0442\u0430\u043b\u044c\u043d\u043e.<\/p>\n<p>\u041d\u043e \u044f \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u043b, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043b\u0443\u0447\u0448\u0435. \u0415\u0441\u043b\u0438 \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c <em>\u043a\u0430\u0436\u0434\u043e\u0435<\/em> \u0438\u043c\u044f, \u0442\u043e, \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c, \u043c\u043e\u0436\u043d\u043e \u0445\u043e\u0442\u044f \u0431\u044b \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u0435\u0449\u0435 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0438\u0445 \u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e?<\/p>\n<h2 id=\"pervaia-popytka-sokrashchaem-privatnye-polia\">\u041f\u0435\u0440\u0432\u0430\u044f \u043f\u043e\u043f\u044b\u0442\u043a\u0430: \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f<\/h2>\n<p>\u042f \u0437\u0430\u043c\u0435\u0442\u0438\u043b \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u0432\u0435\u0449\u044c, \u043a\u043e\u0433\u0434\u0430 \u0441\u043c\u043e\u0442\u0440\u0435\u043b \u043d\u0430 \u043d\u0430\u0448 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434: \u043c\u043d\u043e\u0433\u0438\u0435 \u0434\u043b\u0438\u043d\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u043b\u0438\u0441\u044c \u0441 <code>_<\/code>. \u0412 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u0435 \u0442\u0430\u043a \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f. \u042f \u043f\u043e\u0434\u0443\u043c\u0430\u043b: \u0430\u0433\u0430! \u043a \u043d\u0438\u043c \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0438\u0437\u0432\u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432; \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0431\u0435\u0437\u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u0442\u044c, \u0438 \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u043e\u0434 \u044d\u0442\u043e \u043d\u0435 \u0437\u0430\u0442\u0440\u043e\u043d\u0435\u0442.<\/p>\n<p>\u041c\u0435\u043d\u044f \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e, \u0447\u0442\u043e, \u043f\u043e \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435, \u0441\u0430\u043c <code>esbuild<\/code> \u0442\u0430\u043a \u043d\u0435 \u0434\u0435\u043b\u0430\u043b. \u041d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u043d\u0430 \u044d\u0442\u043e \u0435\u0441\u0442\u044c \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0430, \u043f\u043e\u0434\u0443\u043c\u0430\u043b \u044f. \u0418 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u2014 \u044d\u0442\u043e \u0431\u044b \u0441\u043b\u043e\u043c\u0430\u043b\u043e \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u043e\u043b\u044e \u043f\u043e \u043a\u043b\u044e\u0447\u0443-\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439, \u043a\u0430\u043a \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u044b\u0448\u0435. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, <em>\u0445\u043e\u0440\u043e\u0448\u0438\u0439<\/em> TypeScript-\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 \u0432\u0440\u044f\u0434 \u043b\u0438 \u0441\u0442\u0430\u043b \u0431\u044b \u0442\u0430\u043a \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u043c \u043f\u043e\u043b\u044f\u043c, \u043d\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043c\u0438\u0440\u0435 \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434 \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u0442\u0441\u044f.<\/p>\n<p>\u0421\u0442\u043e\u0438\u0442, \u043a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e <code>private<\/code> \u0432 TypeScript, \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u043d\u0435 \u0442\u0430\u043a\u043e\u0435 \u0443\u0436 \u0441\u0442\u0440\u043e\u0433\u043e\u0435. \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u0432 JavaScript, \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0442\u0438\u0440\u0430\u0435\u0442 \u044d\u0442\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044f \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0432 \u043e\u0431\u044b\u0447\u043d\u044b\u0435. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043c\u0435\u0448\u0430\u0435\u0442 <em>\u043d\u0435\u0432\u043e\u0441\u043f\u0438\u0442\u0430\u043d\u043d\u043e\u043c\u0443<\/em> \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0443 \u0437\u0430\u043b\u0435\u0437\u0442\u044c \u043f\u0440\u044f\u043c\u043e \u0432 \u043a\u0438\u0448\u043e\u0447\u043a\u0438 \u043a\u043b\u0430\u0441\u0441\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"typescript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">class<\/span><span class=\"z-entity z-name z-type\"> Foo<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  private<\/span><span class=\"z-variable z-object z-property\"> bar<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 123<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-ts\"> foo<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Foo<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">foo<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-ts\">bar<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0412\u0430\u0448 \u043a\u043e\u0434 <em>(\u044f \u043d\u0430\u0434\u0435\u044e\u0441\u044c)<\/em> \u0432\u0440\u044f\u0434 \u043b\u0438 \u0434\u0435\u043b\u0430\u0435\u0442 \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435, \u043d\u043e \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u043c\u043e\u0436\u0435\u0442 \u0430\u0443\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u0442\u044b\u0441\u044f\u0447\u0435\u0439 \u0447\u0440\u0435\u0437\u0432\u044b\u0447\u0430\u0439\u043d\u043e \u0432\u0435\u0441\u0435\u043b\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432: \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 <code>{ ...spread }<\/code>, \u043f\u0440\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u043e\u043c \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u043d \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u043a VS Code, \u043e\u0434\u043d\u0430\u043a\u043e, \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e: \u043d\u0430\u0448 \u043a\u043e\u0434 \u0430\u0434\u0435\u043a\u0432\u0430\u0442\u043d\u043e\u0433\u043e (\u043f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438) \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430. \u042f \u0432\u043f\u043e\u043b\u043d\u0435 \u043c\u043e\u0433 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u043a \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u043c \u043f\u043e\u043b\u044f\u043c \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u043a\u043b\u044e\u0447\u0443-\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0438\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 <code>any<\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043c\u043e\u0433 \u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441\u043c\u0435\u043b\u0435\u0435, \u0447\u0435\u043c <code>esbuild<\/code>.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u044f \u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/twitter.com\/johannesrieken\">\u0419\u043e\u0445\u0430\u043d\u043d\u0435\u0441 \u0420\u0438\u043a\u0435\u043d<\/a> \u0441\u0442\u0430\u043b\u0438 \u0438\u0441\u043a\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043d \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439. \u041d\u0430\u0448\u0435\u0439 \u043f\u0435\u0440\u0432\u043e\u0439 \u0438\u0434\u0435\u0435\u0439 \u0431\u044b\u043b\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \"\u0432 \u0441\u0442\u0438\u043b\u0435 TypeScript\" (<code>private foo<\/code>) \u043d\u0430 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Classes\/Private_class_fields\">\"\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435\" \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f<\/a> \u0438\u0437 JavaScript (<code>#foo<\/code>). \u041e\u043d\u0438 \u043b\u0438\u0448\u0435\u043d\u044b \u0432\u0441\u0435\u0445 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0432\u044b\u0448\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 <code>esbuild<\/code> \u0441 \u0440\u0430\u0434\u043e\u0441\u0442\u044c\u044e \u0438\u0445 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u0435\u0442. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043e\u0442 TS-\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0439 \u0444\u0438\u0447\u0438 \u0432 \u043f\u043e\u043b\u044c\u0437\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0439 \u0432 \u0447\u0438\u0441\u0442\u043e\u043c JS.<\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043c\u044b \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u043e\u043d\u044f\u043b\u0438, \u0447\u0442\u043e \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f. \u0412 \u043a\u043e\u0434 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0432\u043d\u0435\u0441\u0442\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439; \u043a\u0440\u043e\u043c\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0447\u0435\u0433\u043e, \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0443\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/2\/classes.html#parameter-properties\">parameter properties<\/a>, \u0434\u0430\u0436\u0435 \u0442\u0430\u043c, \u0433\u0434\u0435 \u043e\u043d\u0438 \u0434\u0435\u043b\u0430\u044e\u0442 \u043a\u043e\u0434 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0447\u0438\u0442\u0430\u0435\u043c\u0435\u0435. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u2014 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043d\u043e\u0432\u0430\u044f \u0434\u043b\u044f JavaScript \u0444\u0438\u0447\u0430, \u0438 \u043d\u0435 \u0432\u0435\u0437\u0434\u0435 \u043e\u043d\u0430 \u0443\u0436\u0435 \u0445\u043e\u0440\u043e\u0448\u043e \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0430. \u0412 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445, \u043a\u043e\u0434 \u0441 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/bugs.webkit.org\/show_bug.cgi?id=258660\">\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435 \u043d\u0430 95%<\/a>! \u0412 \u0431\u0443\u0434\u0443\u0449\u0435\u043c, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 JS \u0431\u044b\u043b\u043e \u0431\u044b \u0434\u043b\u044f \u043d\u0430\u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u2014 \u043d\u043e \u043d\u0435 \u0441\u0435\u0439\u0447\u0430\u0441.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435, \u043c\u044b \u043e\u0431\u0440\u0430\u0442\u0438\u043b\u0438 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e <code>esbuild<\/code> \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u0430 \u0443 \u0442\u0435\u0445 \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u0430\u0442\u0447\u0430\u0442\u0441\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u043c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c. \u042d\u0442\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c\u0438\u0445 \u0438\u043c\u0435\u043d \u2014 \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0432\u0440\u043e\u0434\u0435 <code>private<\/code> \u2014 \u043d\u043e \u043c\u044b \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u043b\u0438, \u0447\u0442\u043e \u0432\u0441\u0435 \u043d\u0430\u0448\u0438 <code>private<\/code> \u0438 <code>protected<\/code>-\u043f\u043e\u043b\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0441 \u0441\u0438\u043c\u0432\u043e\u043b\u0430 <code>_<\/code>. \u0414\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043a\u043e\u043d\u0444\u0438\u0433 <code>esbuild<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u043b \u0432\u0441\u0435 \u0442\u0430\u043a\u0438\u0435 \u0438\u043c\u0435\u043d\u0430.<\/p>\n<p>\u0418 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u0438, \u0447\u0442\u043e \u0432\u0441\u0435 \u043d\u0435 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0435 \u0432\u0435\u0437\u0434\u0435 \u0432 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u0435 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442 \u0441 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0438\u043d\u043e\u0433\u0434\u0430 \u0441 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f <em>\u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0435<\/em> \u043f\u043e\u043b\u044f \u2014 \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0442\u0430\u043c, \u0433\u0434\u0435 \u043f\u043e\u043b\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u0438\u0437\u0432\u043d\u0435, \u043d\u043e \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0447\u0430\u0441\u0442\u044c\u044e API; \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0442\u0435\u0441\u0442\u0430\u0445.<\/p>\n<p>\u041c\u044b \u043d\u0435 \u0431\u044b\u043b\u0438 \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u0448 \u043a\u043e\u0434 \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u043c. \u0412 \u044d\u0442\u043e\u043c, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u043f\u0443\u0442\u0435\u043c \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u0441\u0432\u0435\u0447 \u044d\u0442\u043e \u043d\u0435 \u0441\u0442\u043e\u0438\u0442, \u0434\u0430 \u0438 \u0441\u0442\u043e\u043f\u0440\u043e\u0446\u0435\u043d\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0447\u0440\u0435\u0437\u0432\u044b\u0447\u0430\u0439\u043d\u043e \u0442\u0440\u0443\u0434\u043d\u043e.<\/p>\n<h2 id=\"sokrashchaem-privatnye-polia-s-pomoshch-iu-typescript\">\u0421\u043e\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e TypeScript<\/h2>\n<p>\u041d\u0430\u0448\u0435\u0439 \u043d\u043e\u0432\u043e\u0439 \u0438\u0434\u0435\u0435\u0439 \u0431\u044b\u043b\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435: \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u0431\u044b \u043c\u044b \u0441\u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c TypeScript \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u043e\u043b\u044f \u0431\u044b\u043b\u0438 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u044b \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e? \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0432\u0435\u0434\u044c \u0443\u043c\u0435\u0435\u0442 \u043e\u0442\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u043d\u0435\u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c. \u041c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u0430 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 <em>\u0434\u043e<\/em> \u0432\u044b\u0437\u043e\u0432\u0430 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 TypeScript, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0440\u0443\u0433\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0437\u0430\u0431\u044b\u0442\u043e\u0435 \u0433\u0434\u0435-\u0442\u043e \u0441\u0442\u0430\u0440\u043e\u0435 \u0438\u043c\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0438\u0433\u0434\u0435 \u043d\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043e.<\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u0432 \u0440\u0430\u0441\u043f\u043e\u0440\u044f\u0436\u0435\u043d\u0438\u0438 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 TypeScript-\u043a\u043e\u0434, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c \u0438\u0437 \u043d\u0435\u0433\u043e \u0438 \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0438\u043c\u0435\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0445 \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f <code>private<\/code>, \u0431\u0435\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435 \u0432 \u043a\u0430\u0436\u0434\u043e\u0435 \u0438\u043c\u044f. \u041c\u044b \u0434\u0430\u0436\u0435 \u043c\u043e\u0436\u0435\u043c \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0440\u0443\u043a\u0430\u043c\u0438 \u043a\u043e\u0434 \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u2014 \u0432 TypeScript \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u043e\u0432.<\/p>\n<p>\u0412\u043e\u0442 \u043f\u0441\u0435\u0432\u0434\u043e\u043a\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0435\u0433\u043e\u0441\u044f \u0443 \u043d\u0430\u0441 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043d \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f TypeScript AST, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0441\u0435 private \u0438 protected \u043f\u043e\u043b\u044f \u0432 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span>\u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u043b\u044f:<\/span><\/span>\n<span class=\"giallo-l\"><span>    \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u0435 \u043f\u043e\u0434\u043b\u0435\u0436\u0438\u0442 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044e:<\/span><\/span>\n<span class=\"giallo-l\"><span>        \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u043c\u044f<\/span><\/span>\n<span class=\"giallo-l\"><span>        \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c TypeScript-\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433, \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u043f\u043e\u043b\u0435<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span>\u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0438<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span>\u043e\u0442\u0434\u0430\u0442\u044c TypeScript \u043d\u0430 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a<\/span><\/span><\/code><\/pre>\n<p>\u042d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043d\u0430\u0438\u0432\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c, \u043d\u043e \u043e\u043d, \u043f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442! \u041d\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b \u043d\u0430\u043c \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0435\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u0440\u0430\u0439\u043d\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432:<\/p>\n<ul>\n<li>\n<p>\u041d\u043e\u0432\u043e\u0435 \u0438\u043c\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u044f \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430, \u043d\u043e \u0438 \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0432\u0441\u0435\u0445 \u0435\u0433\u043e \u043f\u0440\u0435\u0434\u043a\u043e\u0432 \u0438 \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432. \u041f\u0440\u0438\u0447\u0438\u043d\u0430, \u043e\u043f\u044f\u0442\u044c-\u0442\u0430\u043a\u0438, \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e <code>private<\/code> \u0432 TypeScript \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438, \u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043c\u0435\u0448\u0430\u0435\u0442 \u043a\u043b\u0430\u0441\u0441\u0430\u043c \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435 \u0437\u0430\u043b\u0435\u0437\u0442\u044c \u0432 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u0435\u0434\u043a\u043e\u0432 \u0438\u043b\u0438 \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, TypeScript \u0432\u044b\u0434\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438, \u0435\u0441\u043b\u0438 \u0432\u0438\u0434\u0438\u0442 \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u044e \u043f\u043e\u043b\u0435\u0439 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438 \u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043c\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b, \u043a\u043b\u0430\u0441\u0441\u044b-\u043f\u043e\u0442\u043e\u043c\u043a\u0438 \u0434\u0435\u043b\u0430\u043b\u0438 \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c. \u0412\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u043f\u043e \u043e\u0448\u0438\u0431\u043a\u0435, \u043d\u043e \u043c\u044b \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0432 \u043d\u0430\u0448 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u044d\u0442\u0438\u0445 \u043a\u0440\u0430\u0439\u043d\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432, \u043c\u044b \u0441\u0442\u0430\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0431\u0438\u043b\u0434\u044b. \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0432 \u043d\u0430\u0448 \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 <code>workbench.js<\/code>, \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 VS Code, \u043c\u044b \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b\u0438, \u0447\u0442\u043e \u0435\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b\u0441\u044f \u0441 12.3 \u041c\u0411 \u0434\u043e 10.6 \u041c\u0411 \u2014 \u043f\u043e\u0447\u0442\u0438 \u043d\u0430 14%. \u042d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0434\u0430\u0436\u0435 \u043d\u0435\u043f\u043b\u043e\u0445\u043e, \u0435\u0441\u043b\u0438 \u0443\u0447\u0435\u0441\u0442\u044c, \u0447\u0442\u043e \u043d\u0430\u043c \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0430\u043c \u043a\u043e\u0434!<\/p>\n<h2 id=\"dal-neishie-issledovaniia\">\u0414\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f<\/h2>\n<p>\u041d\u0430\u0448 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 \u0441 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u0438\u043c\u0435\u043d \u043f\u043e\u043a\u0430\u0437\u0430\u043b, \u0447\u0442\u043e \u0432 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u0435 \u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 VS Code \u0432\u0441\u0435 \u0435\u0449\u0435 \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0438 \u0431\u044b \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0437\u0430\u0442\u0440\u0430\u0442 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043a\u043e\u0434\u0430. \u041d\u0435 \u0434\u0443\u043c\u0430\u044e, \u0447\u0442\u043e \u044f \u0431\u044b\u043b \u043f\u0435\u0440\u0432\u044b\u043c, \u043a\u0442\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u043b \u0434\u043b\u0438\u043d\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430 \u0432 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u0434\u0435 VS Code; \u043e\u0434\u043d\u0430\u043a\u043e \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0438\u0445 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0441\u043b\u043e\u043c\u0430\u0442\u044c \u0431\u044b\u043b\u043e, \u043a\u0430\u043a \u043c\u044b \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u0438, \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e.<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u0432\u0437\u044f\u043b\u0438\u0441\u044c \u0437\u0430 \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443, \u043c\u044b \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 \u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u2014 \u0438\u043c\u0435\u043d\u0430 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439. \u0417\u0430\u0442\u0435\u043c \u043c\u044b \u043d\u0430\u0448\u043b\u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u0441\u044f TypeScript \u2014 \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u044b \u0438\u0449\u0435\u043c \u0438 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u0438 \u043e\u043d \u0436\u0435 \u043f\u043e\u0442\u043e\u043c \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u043a\u043e\u0434 \u0438 \u0440\u0443\u0433\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0438. \u041e\u0447\u0435\u043d\u044c \u043f\u043e\u043c\u043e\u0433\u043b\u043e \u043d\u0430\u043c \u0438 \u0442\u043e, \u0447\u0442\u043e \u0432 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u0435 \u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u043b\u0443\u0447\u0448\u0438\u043c \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430\u043c TypeScript, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u0435\u0440\u0436\u0438\u043c \u0432\u0435\u0441\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u0434 \u043f\u043e\u043a\u0440\u044b\u0442\u044b\u043c \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u0412\u0441\u0435 \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u043d\u0430\u043c \u0441 \u0419\u043e\u0445\u0430\u043d\u043d\u0435\u0441\u043e\u043c, \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u0432 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043c\u043e\u0433 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u0431\u0438\u043b\u0434\u0430, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u043c\u0435\u0448\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0435 \u043d\u0430\u0434 \u043a\u043e\u0434\u043e\u043c.<\/p>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043f\u0440\u043e\u0441\u0442\u043e\u0440 \u0434\u043b\u044f \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043d \u0435\u0449\u0435 \u043e\u0441\u0442\u0430\u043b\u0441\u044f. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u043c \u043a\u043e\u0434\u0435, \u043a \u043c\u043e\u0435\u043c\u0443 \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u044f \u0432\u0441\u0435 \u0435\u0449\u0435 \u0432\u0438\u0434\u0435\u043b \u0434\u043b\u0438\u043d\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430 \u0432\u0440\u043e\u0434\u0435 <code>provideWorkspaceTrustExtensionProposals<\/code>, \u0438\u043b\u0438 \u2014 \u0438\u0437 \u0441\u0430\u043c\u043e\u0433\u043e \u0437\u0430\u043c\u0435\u0442\u043d\u043e\u0433\u043e \u2014 \u043f\u043e\u0447\u0442\u0438 5 \u0442\u044b\u0441\u044f\u0447 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>localize<\/code>.<\/p>\n<p>\u041f\u043e\u043b\u044c\u0437\u0443\u044f\u0441\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u0432\u044b\u0448\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c, \u044f \u0432\u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u043d\u0430\u0448\u0435\u043b \u0435\u0449\u0435 \u043e\u0434\u043d\u043e \u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c: \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u0438\u043c\u0435\u043d\u0430, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e API. \u042f \u0431\u044b\u043b \u0443\u0432\u0435\u0440\u0435\u043d, \u0447\u0442\u043e \u0438\u0445 \u0442\u043e\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c.<\/p>\n<p>\u0418, \u043f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438, \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0442\u0430\u043a. \u0425\u043e\u0442\u044f \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043e\u043f\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u0440\u0430\u0439\u043d\u0438\u0435 \u0441\u043b\u0443\u0447\u0430\u0438. \u041a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u043d\u0430\u043c \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0442\u0440\u043e\u0433\u0430\u0442\u044c API \u0434\u043b\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 VS Code. \u041c\u044b \u0442\u0430\u043a\u0436\u0435 \u043d\u0435 \u043c\u043e\u0433\u043b\u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u0442\u0435\u043c\u0438 \u0438\u043c\u0435\u043d\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0438\u0437 \u0447\u0438\u0441\u0442\u043e\u0433\u043e JS \u2014 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c, \u044d\u0442\u043e \u0442\u043e\u0447\u043a\u0438 \u0432\u0445\u043e\u0434\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432 \u0438 \u0432\u043e\u0440\u043a\u0435\u0440\u043e\u0432.<\/p>\n<p>\u0421\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u043d \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u043e\u0432 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b\u043e \u0440\u0430\u0437\u043c\u0435\u0440 <code>workbench.js<\/code> \u0435\u0449\u0435 \u0441\u0438\u043b\u044c\u043d\u0435\u0435 \u2014 \u0441 10.6 \u041c\u0411 \u0434\u043e 9.8 \u041c\u0411. \u0412 \u0438\u0442\u043e\u0433\u0435, \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0441\u0442\u0430\u043b \u043d\u0430 20% \u043c\u0435\u043d\u044c\u0448\u0435, \u0447\u0435\u043c \u0431\u044b\u043b, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u043b\u0438. \u041f\u043e \u0432\u0441\u0435\u0439 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u0435 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u043d \u043f\u043e\u043c\u043e\u0433\u043b\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c 3.9 \u041c\u0411 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0433\u043e JavaScript-\u043a\u043e\u0434\u0430. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u043b\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u043d\u044c\u0448\u0438\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435, \u043d\u043e \u0438 \u043c\u0435\u043d\u044c\u0448\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u0442\u0430\u0440\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041d\u0438\u0436\u0435 \u044f \u0435\u0449\u0435 \u0440\u0430\u0437 \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u0433\u0440\u0430\u0444\u0438\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430 <code>workbench.js<\/code> \u043f\u043e \u0432\u0435\u0440\u0441\u0438\u044f\u043c. \u0414\u0432\u0430 \u0440\u0435\u0437\u043a\u0438\u0445 \u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0432 \u043f\u0440\u0430\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u2014 \u044d\u0442\u043e \u044d\u0444\u0444\u0435\u043a\u0442 \u043e\u0442 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043d: \u0438\u043c\u0435\u043d\u0430 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0431\u044b\u043b\u0438 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u044b \u0432 VS Code 1.74, \u0438\u043c\u0435\u043d\u0430 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u043e\u0432 \u2014 \u0432 VS Code 1.80.<\/p>\n<figure class=\"border\">\n<p><img src=\"https:\/\/iliazeus.lol\/translations\/vscode-name-mangling\/graph.png\" alt=\"\u0420\u0430\u0437\u043c\u0435\u0440 workbench.js, \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 VS Code, \u043f\u043e \u0432\u0435\u0440\u0441\u0438\u044f\u043c\" \/><\/p>\n<figcaption>\u0420\u0430\u0437\u043c\u0435\u0440 workbench.js, \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 VS Code, \u043f\u043e \u0432\u0435\u0440\u0441\u0438\u044f\u043c<\/figcaption>\n<\/figure>\n<p>\u0411\u0435\u0437\u0443\u0441\u043b\u043e\u0432\u043d\u043e, \u043d\u0430\u0448\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043d \u0434\u0430\u043b\u0435\u043a\u0430 \u043e\u0442 \u0438\u0434\u0435\u0430\u043b\u0430, \u0438 \u0435\u0449\u0435 \u043c\u043d\u043e\u0433\u043e \u0434\u043b\u0438\u043d\u043d\u044b\u0445 \u0438\u043c\u0435\u043d \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0441\u0431\u043e\u0440\u043a\u0438. \u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u043c\u044b \u0435\u0449\u0435 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u044d\u0442\u043e\u0439 \u0442\u0435\u043c\u0435, \u0435\u0441\u043b\u0438 \u043f\u043e\u0439\u043c\u0435\u043c, \u0447\u0442\u043e \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u0434\u0443\u0442 \u043d\u0430\u043c \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u044b\u0439 \u0432\u044b\u0445\u043b\u043e\u043f, \u0438 \u0435\u0441\u043b\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0445, \u043d\u0435 \u0441\u043b\u043e\u043c\u0430\u0432 \u043a\u043e\u0434. \u0412 \u0431\u0443\u0434\u0443\u0449\u0435\u043c, \u043d\u0430\u043c \u0434\u0430\u0436\u0435, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0447\u0442\u043e-\u0442\u043e \u0441\u0430\u043c\u0438\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u2014 \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u0438 \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u0433\u043e\u0434\u043e\u043c \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0432\u0441\u0435 \u0443\u043c\u043d\u0435\u0435, \u0438 \u0432\u0441\u0435 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u044e\u0442, \u043a\u0430\u043a\u0438\u0435 \u0438\u043c\u0435\u043d\u0430 \u043c\u043e\u0436\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c. \u041d\u0430\u0448\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043d \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/microsoft\/vscode\/blob\/48cd8e0c1b142a46f0956b593d8331145634658e\/build\/lib\/mangle\/index.ts\">\u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435<\/a>.<\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u044d\u0442\u0438\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u044f \u0441\u043c\u043e\u0433 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043d\u0430\u043c \u0432\u0430\u0436\u043d\u0430 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f, \u0438 \u043a\u0430\u043a \u043c\u044b \u043a \u043d\u0435\u0439 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u043c. \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f, \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0438 \u2014 \u044d\u0442\u043e \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441. \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0431\u0438\u043b\u0434\u0430 (\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439), \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0439\u0442\u0438 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b \u0434\u043b\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0433\u043e \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f. \u041c\u044b \u0441\u0442\u0430\u0440\u0430\u0435\u043c\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u043b\u0443\u0447\u0448\u0438\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 TypeScript, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u043e\u044f\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u043e\u0432. \u041c\u044b \u043f\u0438\u0448\u0435\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043d\u0430\u043c \u0431\u044b\u0442\u044c \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u043c\u0438, \u0447\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u043c\u0438 \u0438 \u043d\u0435 \u0441\u043b\u043e\u043c\u0430\u044e\u0442 \u043a\u043e\u0434.<\/p>\n<p>\u042f \u0433\u043e\u0440\u0436\u0443\u0441\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c, \u0438 \u0433\u043e\u0440\u0436\u0443\u0441\u044c \u0442\u0435\u043c, \u043a\u0430\u043a \u043c\u044b \u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0438.<\/p>\n"},{"title":"\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u043e\u043a \u0432 JavaScript-\u0434\u0432\u0438\u0436\u043a\u0435 V8","published":"2023-08-08T00:00:00+00:00","updated":"2023-08-08T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/js-string-optimizations-ru\/"}},"id":"https:\/\/iliazeus.lol\/articles\/js-string-optimizations-ru\/","content":"<p>\u0421 \u0441\u0430\u043c\u043e\u0433\u043e \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f JavaScript, \u0432 \u043a\u0430\u043a\u043e\u043c-\u0442\u043e \u0441\u043c\u044b\u0441\u043b\u0435, \u0431\u044b\u043b, \u0432\u043e \u043c\u043d\u043e\u0433\u043e\u043c, \u044f\u0437\u044b\u043a\u043e\u043c \u0434\u043b\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u043c \u2014 \u043e\u0442 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u0435\u043a \u0432 \u0441\u0430\u043c\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435, \u0434\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u043e\u0432 \u0441\u0435\u0439\u0447\u0430\u0441. \u041d\u0435\u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e \u0432 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 JS-\u0434\u0432\u0438\u0436\u043a\u0430\u0445 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0441\u0438\u043b \u0443\u0434\u0435\u043b\u0435\u043d\u043e \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043d\u0430\u0434 \u043d\u0438\u043c\u0438.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u043a\u0430\u043a \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u0434\u0432\u0438\u0436\u043a\u0435 V8. \u041f\u043e\u043f\u044b\u0442\u0430\u044e\u0441\u044c \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u044d\u0444\u0444\u0435\u043a\u0442, \u043e\u0431\u043e\u0433\u043d\u0430\u0432 C++ \u0432 <em>\u043e\u0447\u0435\u043d\u044c \u0447\u0435\u0441\u0442\u043d\u043e\u043c<\/em> \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0435. \u0410 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u043a\u0430\u0436\u0443, \u0432 \u043a\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442, \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e, \u0438 \u0447\u0442\u043e \u0432 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c.<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/js-string-optimizations-ru\/cover.png\" alt=\"&quot;\u043e\u0431\u0433\u043e\u043d\u044f\u0435\u043c&quot; C++\" \/><\/p>\n<h2 id=\"instrumenty-dlia-issledovaniia\"><a class=\"anchor\" href=\"#instrumenty-dlia-issledovaniia\" title=\"link to section\">#<\/a>\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f<\/h2>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c, \u043a\u0430\u043a\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u0440\u043e\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/v8\/v8\/blob\/941b945b\/src\/runtime\/runtime.h#L20\">\u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 V8<\/a>. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c Node.js \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c <code>--allow-natives-syntax<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">$<\/span><span class=\"z-variable z-other z-readwrite\"> node<\/span><span class=\"z-keyword z-operator\"> --<\/span><span class=\"z-variable z-other z-readwrite\">allow<\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-variable z-other z-readwrite\">natives<\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-variable z-other z-readwrite\">syntax<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">Welcome<\/span><span class=\"z-variable z-other z-readwrite\"> to<\/span><span class=\"z-source\"> Node<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">js<\/span><span class=\"z-variable z-other z-readwrite\"> v20<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-constant z-numeric\">3<\/span><span class=\"z-constant z-numeric\">.<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation z-accessor\">.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">Type<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.help<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-variable z-other z-readwrite\"> for<\/span><span class=\"z-variable z-other z-readwrite\"> more<\/span><span class=\"z-variable z-other z-readwrite\"> information<\/span><span class=\"z-punctuation z-accessor\">.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">123<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-source\"> Smi<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x7b<\/span><span class=\"z-source\"> (<\/span><span class=\"z-constant z-numeric\">123<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">123<\/span><\/span><\/code><\/pre>\n<p>\u0414\u043b\u044f \u0441\u0442\u0440\u043e\u043a \u044d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0435\u0447\u0430\u0442\u0430\u0435\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0431\u0443\u0434\u0443 \u0437\u0430\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0430 <code>\/* ... *\/<\/code> \u0442\u043e, \u0447\u0442\u043e \u043d\u0435 \u0432\u0430\u0436\u043d\u043e \u0434\u043b\u044f \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u044f.<\/p>\n<h2 id=\"kakie-v-v8-est-stroki\"><a class=\"anchor\" href=\"#kakie-v-v8-est-stroki\" title=\"link to section\">#<\/a>\u041a\u0430\u043a\u0438\u0435 \u0432 V8 \u0435\u0441\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438?<\/h2>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439 \u0441\u0442\u0440\u043e\u043a \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/v8\/v8\/blob\/941b945b\/src\/objects\/objects.h#L134-L151\">\u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u0445 V8<\/a>.<\/p>\n<ul>\n<li><code>String<\/code>\n<ul>\n<li><code>SeqString<\/code>\n<ul>\n<li><code>SeqOneByteString<\/code><\/li>\n<li><code>SeqTwoByteString<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>SlicedString<\/code><\/li>\n<li><code>ConsString<\/code><\/li>\n<li><code>ThinString<\/code><\/li>\n<li><code>ExternalString<\/code>\n<ul>\n<li><code>ExternalOneByteString<\/code><\/li>\n<li><code>ExternalTwoByteString<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>InternalizedString<\/code>\n<ul>\n<li><code>SeqInternalizedString<\/code>\n<ul>\n<li><code>SeqOneByteInternalizedString<\/code><\/li>\n<li><code>SeqTwoByteInternalizedString<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>ConsInternalizedString<\/code><\/li>\n<li><code>ExternalInternalizedString<\/code>\n<ul>\n<li><code>ExternalOneByteInternalizedString<\/code><\/li>\n<li><code>ExternalTwoByteInternalizedString<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u0411\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u043c\u043d\u043e\u0433\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432:<\/p>\n<h3 id=\"onebyte-i-twobyte\"><a class=\"anchor\" href=\"#onebyte-i-twobyte\" title=\"link to section\">#<\/a><code>OneByte<\/code> \u0438 <code>TwoByte<\/code><\/h3>\n<p>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/262.ecma-international.org\/14.0\/#sec-ecmascript-language-types-string-type\">\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438<\/a> \u043a\u0430\u043a \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 16-\u0431\u0438\u0442\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u041d\u043e \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u043e 2 \u0431\u0430\u0439\u0442\u0430 \u043d\u0430 \u0441\u0438\u043c\u0432\u043e\u043b \u0431\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0440\u0430\u0441\u0442\u043e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e. \u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435, \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043d\u0435 \u0432\u044b\u0445\u043e\u0434\u044f\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 ASCII. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u043d\u0443\u0442\u0440\u0438 V8 \u0441\u0442\u0440\u043e\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u043e\u0434\u043d\u043e-, \u0442\u0430\u043a \u0438 \u0434\u0432\u0443\u0445\u0431\u0430\u0439\u0442\u043e\u0432\u044b\u043c\u0438.<\/p>\n<p>\u041a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0432\u043e\u0442 ASCII-\u0441\u0442\u0440\u043e\u043a\u0430. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0435\u0435 <code>type<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x209affbb9309<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-source\"> OldSpace<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-source\"> #<\/span><span class=\"z-variable z-other z-readwrite\">hello<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0x30f098a80299<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_INTERNALIZED_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre>\n<p>\u0410 \u0432\u043e\u0442 \u0441\u0442\u0440\u043e\u043a\u0430 \u0441 \u043d\u0435-ASCII \u0441\u0438\u043c\u0432\u043e\u043b\u0430\u043c\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043a\u0430\u043a \u0434\u0432\u0443\u0445\u0431\u0430\u0439\u0442\u043e\u0432\u0430\u044f:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">\u043f\u0440\u0438\u0432\u0435\u0442<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x1b10a9ba2291<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-source\"> OldSpace<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-readwrite\"> u<\/span><span class=\"z-source\">#\\<\/span><span class=\"z-variable z-other z-readwrite\">u043f<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0440<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0438<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0432<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0435<\/span><span class=\"z-source\">\\<\/span><span class=\"z-variable z-other z-readwrite\">u0442<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0x30f098a81e29<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> INTERNALIZED_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre><h3 id=\"internalized\"><a class=\"anchor\" href=\"#internalized\" title=\"link to section\">#<\/a><code>Internalized<\/code><\/h3>\n<p>\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u2014 \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0432\u0441\u0435 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0435 \u043b\u0438\u0442\u0435\u0440\u0430\u043b\u044b \u0438\u043d\u0442\u0435\u0440\u043d\u0438\u0440\u0443\u0442\u0441\u044f \u2014 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0434\u0432\u0438\u0436\u043a\u043e\u043c \u0432 \u0435\u0434\u0438\u043d\u044b\u0439 \u043f\u0443\u043b \u0441\u0442\u0440\u043e\u043a, \u0432\u043d\u0435 \u043a\u0443\u0447\u0438. \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0445 \u043b\u0438\u0442\u0435\u0440\u0430\u043b\u043e\u0432 \u044d\u0442\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f. \u0422\u0430\u043a\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u043c\u0435\u044e\u0442 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0442\u043f\u0438 <code>Internalized<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x209affbb9309<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-source\"> OldSpace<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-source\"> #<\/span><span class=\"z-variable z-other z-readwrite\">hello<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0x30f098a80299<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_INTERNALIZED_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435, \u0442\u043e \u043e\u043d\u0430, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 <code>INTERNALIZED<\/code> \u0432 \u0435\u0435 <code>type<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-storage z-type\"> var<\/span><span class=\"z-variable z-other z-readwrite\"> fs<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> require<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">fs<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writeFileSync<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">utf8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-storage z-type\"> var<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">readFileSync<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">utf8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">s<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x2c6f46782469<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">hello<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec0879<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043c\u0435\u0448\u0430\u0435\u0442 \u0434\u0432\u0438\u0436\u043a\u0443 \u0438\u043d\u0442\u0435\u0440\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0437\u0436\u0435. \u041e\u0434\u0438\u043d \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u2014 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u0432\u0438\u0436\u043e\u043a \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0435\u0435 \u043a\u0430\u043a \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0439 \u043b\u0438\u0442\u0435\u0440\u0430\u043b \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <code>eval<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-storage z-type\"> var<\/span><span class=\"z-variable z-other z-readwrite\"> ss<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> eval<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-language z-undefined z-js\">undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">ss<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x80160fa1809<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-source\"> OldSpace<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-source\"> #<\/span><span class=\"z-variable z-other z-readwrite\">hello<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec0299<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_INTERNALIZED_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre><h3 id=\"external\"><a class=\"anchor\" href=\"#external\" title=\"link to section\">#<\/a><code>External<\/code><\/h3>\n<p><code>External<\/code>-\u0441\u0442\u0440\u043e\u043a\u0438 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043d\u0435 \u043d\u0430 \u043a\u0443\u0447\u0435, \u0430 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043e\u0431\u043b\u0430\u0441\u0442\u044f\u0445 \u043f\u0430\u043c\u044f\u0442\u0438, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u043d\u0438\u0445 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u044d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0447\u0435\u043d\u044c \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0441\u0442\u0440\u043e\u043a. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c Node.js \u0441 \u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u043a\u0443\u0447\u0438, \u043d\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u043c \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a\u0438 \u043c\u043d\u043e\u0433\u043e \u043f\u0430\u043c\u044f\u0442\u0438:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> test.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0443 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0432 16 \u041c\u0411<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">var<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Buffer<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">alloc<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">16<\/span><span class=\"z-keyword z-operator\"> *<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-keyword z-operator\"> *<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-constant z-numeric\"> 20<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 65<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toString<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">ascii<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435\u043c \u043a\u0443\u0447\u0438 \u0432 8 \u041c\u0411:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=8<\/span><span class=\"z-string\"> test.js<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">16777216<\/span><\/span><\/code><\/pre><h3 id=\"sliced\"><a class=\"anchor\" href=\"#sliced\" title=\"link to section\">#<\/a><code>Sliced<\/code><\/h3>\n<p>\u0414\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u043f\u0430\u043c\u044f\u0442\u0438 \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0432\u0437\u044f\u0442\u0438\u044f \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>Sliced<\/code>-\u0441\u0442\u0440\u043e\u043a\u0443. \u042d\u0442\u043e \u0430\u043d\u0430\u043b\u043e\u0433 string view \u0438\u0437 \u0434\u0440\u0443\u0433\u0438\u0445 \u044f\u0437\u044b\u043a\u043e\u0432 \u2014 \u0442\u043e \u0435\u0441\u0442\u044c, \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0443-\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f, \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0438 \u0434\u043b\u0438\u043d\u0430.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-storage z-type\"> var<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Buffer<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">alloc<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">256<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 65<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toString<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-string\">ascii<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-language z-undefined z-js\">undefined<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">slice<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 15<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x80e9bea9851<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">AAAAAAAAAAAAAAA<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec1d09<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> SLICED_ONE_BYTE_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre>\n<p>\u041d\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043a\u043e\u0440\u043e\u0442\u043a\u0430\u044f, \u0442\u043e \u0432\u044b\u0433\u043e\u0434\u043d\u0435\u0435 \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u0435\u0435 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">slice<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 5<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x18a9c2e10169<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">AAAAA<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec0879<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre><h3 id=\"cons\"><a class=\"anchor\" href=\"#cons\" title=\"link to section\">#<\/a><code>Cons<\/code><\/h3>\n<p>\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e, \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u043a\u043e\u043d\u043a\u0430\u0442\u0435\u043d\u0430\u0446\u0438\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>Cons<\/code>-\u0441\u0442\u0440\u043e\u043a\u0443, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0443\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043b\u0435\u0432\u0443\u044e \u0438 \u043f\u0440\u0430\u0432\u0443\u044e \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">s<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-variable z-other z-readwrite\"> s<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0x2c6f467b3e09<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-variable z-other z-readwrite\">c<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">AAAAAAAAAA\/* ... *\/AA<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec1be9<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> CONS_ONE_BYTE_STRING_TYPE<\/span><\/span><\/code><\/pre>\n<p>\u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u043e\u043f\u044f\u0442\u044c-\u0442\u0430\u043a\u0438, \u0434\u043b\u044f \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0445 \u0441\u0442\u0440\u043e\u043a \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-keyword z-operator\"> %<\/span><span class=\"z-entity z-name z-function\">DebugPrint<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">slice<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-source\"> s<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">slice<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">0<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 3<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">DebugPrint<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 0xec9b3412501<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">String<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">AAAAA<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-constant z-numeric\">0xd2880ec0879<\/span><span class=\"z-source\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-variable z-other z-readwrite\">Map<\/span><span class=\"z-source\">]<\/span><span class=\"z-keyword z-operator z-expression z-in z-js\"> in<\/span><span class=\"z-variable z-other z-readwrite\"> ReadOnlySpace<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-source\"> type<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-variable z-other z-constant z-js\"> ONE_BYTE_STRING_TYPE<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> \/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span><\/code><\/pre><h2 id=\"preimushchestva-optimizatsii-obgoniaem-c\"><a class=\"anchor\" href=\"#preimushchestva-optimizatsii-obgoniaem-c\" title=\"link to section\">#<\/a>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0439: \"\u043e\u0431\u0433\u043e\u043d\u044f\u0435\u043c\" C++<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 V8. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u044d\u0442\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u043c\u043e\u0438\u0445 \u043b\u044e\u0431\u0438\u043c\u044b\u0445 \u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d: \u043d\u0435\u0447\u0435\u0441\u0442\u043d\u044b\u0445 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f\u0445 \u0440\u0430\u0437\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432!<\/p>\n<p>\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u0440\u043e\u0441\u0442\u044b: \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 JS-\u043a\u043e\u0434 \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u0447\u0435\u043c \u0441\u0442\u0440\u043e\u0447\u043a\u0430-\u0432-\u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u0430 C++. \u041a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e, \u0447\u0442\u043e <code>Cons<\/code>-\u0441\u0442\u0440\u043e\u043a\u0438 \u0434\u0430\u044e\u0442 \u043d\u0430\u043c \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u0443\u044e \u043a\u043e\u043d\u043a\u0430\u0442\u0435\u043d\u0430\u0446\u0438\u044e, \u0430 <code>Sliced<\/code>-\u0441\u0442\u0440\u043e\u043a\u0438 \u2014 \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u043e\u0435 \u0432\u0437\u044f\u0442\u0438\u0435 \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0438.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> unethical-benchmark.js<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0434\u0430\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 text \u0434\u043b\u0438\u043d\u043e\u0439 1500<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043d\u0430\u0439\u0442\u0438 \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u0443\u044e \u0434\u043b\u0438\u043d\u0443 \u0442\u0435\u0445 \u0435\u0451 \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u043b\u0438\u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 200<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> text<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">a<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">repeat<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">1500<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> result<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> j<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-constant z-numeric\"> 201<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> j<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> j<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    result<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">substr<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">i<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> j<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">result<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u0443\u0449\u0435\u0439 <em>\u0447\u0435\u0441\u0442\u043d\u043e\u0441\u0442\u0438<\/em> \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0430 \u0433\u043e\u043b\u043e\u043c V8, \u0441\u043a\u0430\u0447\u0430\u0432 \u0435\u0433\u043e \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/jsvu\">jsvu<\/a>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> time<\/span><span class=\"z-string\"> ~\/.jsvu\/bin\/v8<\/span><span class=\"z-string\"> unethical-benchmark.js<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">535036450<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">real<\/span><span class=\"z-string\">    0m0.145s<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">user<\/span><span class=\"z-string\">    0m0.122s<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">sys<\/span><span class=\"z-string\">     0m0.028s<\/span><\/span><\/code><\/pre>\n<p>\u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u0441\u0442\u0440\u043e\u043a\u0430-\u0432-\u0441\u0442\u0440\u043e\u043a\u0443 \u043a\u043e\u0434 \u043d\u0430 C++:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> unethical-benchmark.cxx<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0434\u0430\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 text \u0434\u043b\u0438\u043d\u043e\u0439 1500<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u043d\u0430\u0439\u0442\u0438 \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u0443\u044e \u0434\u043b\u0438\u043d\u0443 \u0442\u0435\u0445 \u0435\u0451 \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u043b\u0438\u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 200<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">include<\/span><span class=\"z-punctuation z-definition z-string\"> &lt;<\/span><span class=\"z-string\">iostream<\/span><span class=\"z-punctuation z-definition z-string\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-directive\">#<\/span><span class=\"z-keyword z-control z-directive\">include<\/span><span class=\"z-punctuation z-definition z-string\"> &lt;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">int<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">  std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">string<\/span><span class=\"z-entity z-name z-function\"> text<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-constant z-numeric\">1500<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">a<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">  std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">string result<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-storage z-type\">int<\/span><span class=\"z-source\"> i <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-source\"> i <\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">length<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-source\"> i<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-storage z-type\">int<\/span><span class=\"z-source\"> j <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> i <\/span><span class=\"z-keyword z-operator\">+<\/span><span class=\"z-constant z-numeric\"> 201<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-source\"> j <\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">length<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-source\"> j<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      result <\/span><span class=\"z-keyword z-operator\">+=<\/span><span class=\"z-source\"> text<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">substr<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">i<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> j <\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-source\"> i<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-scope-resolution z-cpp\">  std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">cout <\/span><span class=\"z-keyword z-operator\">&lt;&lt;<\/span><span class=\"z-source\"> result<\/span><span class=\"z-punctuation\">.<\/span><span class=\"z-entity z-name z-function\">length<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\"> &lt;&lt;<\/span><span class=\"z-entity z-name z-scope-resolution z-cpp\"> std<\/span><span class=\"z-punctuation\">::<\/span><span class=\"z-source\">endl<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> g++<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">O3<\/span><span class=\"z-string\"> unethical-benchmark.cxx<\/span><span class=\"z-punctuation\"> &amp;&amp;<\/span><span class=\"z-keyword\"> time<\/span><span class=\"z-source\"> .\/a.out<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">535036450<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">real<\/span><span class=\"z-string\">    0m0.324s<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">user<\/span><span class=\"z-string\">    0m0.176s<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">sys<\/span><span class=\"z-string\">     0m0.147s<\/span><\/span><\/code><\/pre>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u044d\u0442\u043e \u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0430 \u043d\u0435\u043c \u0445\u043e\u0440\u043e\u0448\u043e \u0432\u0438\u0434\u0435\u043d \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0444\u0444\u0435\u043a\u0442 \u043e\u0442 <code>Cons<\/code>- \u0438 <code>Sliced<\/code>-\u0441\u0442\u0440\u043e\u043a. \u0410 \u0438\u043c\u0435\u043d\u043d\u043e: \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043d\u0430\u0438\u0432\u043d\u044b\u0439 \u043a\u043e\u0434, \u0431\u0435\u0437 \u0432\u0441\u044f\u043a\u0438\u0445 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0439, \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435.<\/p>\n<h2 id=\"nedostatki-optimizatsii-uchimsia-otmyvat-stroki\"><a class=\"anchor\" href=\"#nedostatki-optimizatsii-uchimsia-otmyvat-stroki\" title=\"link to section\">#<\/a>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0439: \u0443\u0447\u0438\u043c\u0441\u044f \"\u043e\u0442\u043c\u044b\u0432\u0430\u0442\u044c\" \u0441\u0442\u0440\u043e\u043a\u0438<\/h2>\n<p>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a \u0442\u0430\u043a\u0438\u0445 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0439 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0438\u043c\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0442\u0440\u0443\u0434\u043d\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c. \u0412 \u0434\u0440\u0443\u0433\u0438\u0445 \u044f\u0437\u044b\u043a\u0430\u0445 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 \u043c\u043e\u0436\u0435\u0442 \u044f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u0433\u0434\u0435 \u0435\u043c\u0443 \u043d\u0443\u0436\u0435\u0442 string view, \u0433\u0434\u0435 string builder, \u0430 \u0433\u0434\u0435 \u043e\u0434\u043d\u043e\u0431\u0430\u0439\u0442\u043e\u0432\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u2014 \u043d\u043e \u0432 JS \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043b\u0438\u0431\u043e \u0442\u0435\u0440\u043f\u0435\u0442\u044c \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044f \u0434\u0432\u0438\u0436\u043a\u0430, \u043b\u0438\u0431\u043e \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043b\u0434\u0443\u043d\u0441\u0442\u0432\u043e\u043c.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0442\u0430\u0449\u0438\u0442 \u043d\u0430\u043c \u0432\u0441\u0435 \u0430\u0434\u0440\u0435\u0441\u0430 \u0441\u0441\u044b\u043b\u043e\u043a \u0438\u0437 \u043f\u0430\u0440\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u043e\u0432 \u0425\u0430\u0431\u0440\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> urls-1.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  ]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">pageUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">text<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-source\"> html<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">matchAll<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string z-begin\">\/<\/span><span class=\"z-string\">href=&quot;<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">(<\/span><span class=\"z-constant z-other z-character-class z-regexp\">.<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">*<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">?<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">)<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string z-end\">\/<\/span><span class=\"z-keyword\">g<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      linkUrls<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0441 \u043a\u0430\u043a\u0438\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u043a\u0443\u0447\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0435\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=10<\/span><span class=\"z-string\"> urls-1.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><span class=\"z-punctuation z-definition z-comment\"> #<\/span><span class=\"z-comment\"> \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=9<\/span><span class=\"z-string\"> urls-1.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- Last few GCs ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">252407:0x55b40628dbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     2894 ms: Mark-Compact 10.8 (<\/span><span class=\"z-entity z-name z-function\">13.7<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 8.5 (<\/span><span class=\"z-entity z-name z-function\">16.9<\/span><span class=\"z-source\">) MB, 9.22 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.989,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.683<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> scavenge<\/span><span class=\"z-string\"> might<\/span><span class=\"z-string\"> not<\/span><span class=\"z-string\"> succeed<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">252407:0x55b40628dbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     2906 ms: Mark-Compact (<\/span><span class=\"z-entity z-name z-function\">reduce<\/span><span class=\"z-source\">) 9.7 (<\/span><span class=\"z-entity z-name z-function\">16.9<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 9.1 (<\/span><span class=\"z-entity z-name z-function\">10.4<\/span><span class=\"z-source\">) MB, 2.68 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">+<\/span><span class=\"z-constant z-numeric\"> 0.9<\/span><span class=\"z-string\"> ms<\/span><span class=\"z-string\"> in<\/span><span class=\"z-constant z-numeric\"> 12<\/span><span class=\"z-string\"> steps<\/span><span class=\"z-string\"> since<\/span><span class=\"z-string\"> start<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> marking,<\/span><span class=\"z-string\"> biggest<\/span><span class=\"z-string\"> step<\/span><span class=\"z-constant z-numeric\"> 0.1<\/span><span class=\"z-string\"> ms,<\/span><span class=\"z-string\"> walltime<\/span><span class=\"z-string\"> since<\/span><span class=\"z-string\"> start<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> marking<\/span><span class=\"z-constant z-numeric\"> 10<\/span><span class=\"z-string\"> ms<\/span><span class=\"z-source\">) (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.984,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.681<\/span><span class=\"z-source\">) fina<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- JS stacktrace ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">FATAL<\/span><span class=\"z-string\"> ERROR:<\/span><span class=\"z-string\"> Reached<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> limit<\/span><span class=\"z-string\"> Allocation<\/span><span class=\"z-string\"> failed<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> JavaScript<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> out<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> memory<\/span><\/span><\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0432 10 \u041c\u0411 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0430 \u0432\u043e\u0442 \u043f\u0440\u0438 9 \u041c\u0411 \u0443\u0436\u0435 \u043f\u0430\u0434\u0430\u0435\u0442.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c. \u0418\u0437 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0445 \u0438\u0434\u0435\u0439 \u2014 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 <code>html<\/code>, \u0434\u0430\u0436\u0435 \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0443\u0436\u0435 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0437\u0430\u043d\u0443\u043b\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e, \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u0443\u0442\u0430\u0449\u0438\u043b\u0430 \u0441\u0431\u043e\u0440\u043a\u0430 \u043c\u0443\u0441\u043e\u0440\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> urls-2.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  ]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">pageUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">text<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-source\"> html<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">matchAll<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string z-begin\">\/<\/span><span class=\"z-string\">href=&quot;<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">(<\/span><span class=\"z-constant z-other z-character-class z-regexp\">.<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">*<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">?<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">)<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string z-end\">\/<\/span><span class=\"z-keyword\">g<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      linkUrls<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> &lt;---<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=9<\/span><span class=\"z-string\"> urls-2.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- Last few GCs ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">252792:0x5576c8da8bb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     3078 ms: Mark-Compact 8.9 (<\/span><span class=\"z-entity z-name z-function\">12.3<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 7.3 (<\/span><span class=\"z-entity z-name z-function\">12.3<\/span><span class=\"z-source\">) MB, 6.65 \/ 0.02 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.997,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.994<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> scavenge<\/span><span class=\"z-string\"> might<\/span><span class=\"z-string\"> not<\/span><span class=\"z-string\"> succeed<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">252792:0x5576c8da8bb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     3101 ms: Mark-Compact 10.7 (<\/span><span class=\"z-entity z-name z-function\">13.4<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 8.5 (<\/span><span class=\"z-entity z-name z-function\">17.4<\/span><span class=\"z-source\">) MB, 6.27 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.992,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.725<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> scavenge<\/span><span class=\"z-string\"> might<\/span><span class=\"z-string\"> not<\/span><span class=\"z-string\"> succeed<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- JS stacktrace ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">FATAL<\/span><span class=\"z-string\"> ERROR:<\/span><span class=\"z-string\"> Reached<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> limit<\/span><span class=\"z-string\"> Allocation<\/span><span class=\"z-string\"> failed<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> JavaScript<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> out<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> memory<\/span><\/span><\/code><\/pre>\n<p>\u041d\u0435 \u043f\u043e\u043c\u043e\u0433\u043b\u043e! \u041f\u0440\u0438\u0447\u0438\u043d\u0430, \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u043e\u0441\u043e\u0431\u044b\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0441\u0442\u0440\u043e\u043a: \u0432\u0441\u0435 <code>urls<\/code> \u2014 \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0438 <code>html<\/code>, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u043a\u0430\u043a <code>Sliced<\/code>-\u0441\u0442\u0440\u043e\u043a\u0438; \u043e\u043d\u0438 \u0445\u0440\u0430\u043d\u044f\u0442 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 <code>html<\/code>, \u043d\u0435 \u0434\u0430\u0432\u0430\u044f \u0435\u043c\u0443 \u0441\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u043c\u0443\u0441\u043e\u0440.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/habr.com\/ru\/articles\/449368\/\">\u043e\u0442\u043c\u043e\u0435\u043c<\/a> \u044d\u0442\u0438 \u0441\u0442\u0440\u043e\u043a\u0438!<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> urls-3.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  ]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">pageUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">text<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-source\"> html<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">matchAll<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string z-begin\">\/<\/span><span class=\"z-string\">href=&quot;<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">(<\/span><span class=\"z-constant z-other z-character-class z-regexp\">.<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">*<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">?<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">)<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string z-end\">\/<\/span><span class=\"z-keyword\">g<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-constant\"> JSON<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">parse<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-constant\">JSON<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">stringify<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> &lt;---<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      linkUrls<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u043c\u0430\u0433\u0438\u044f. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043b\u0438?<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=9<\/span><span class=\"z-string\"> urls-3.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442!<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=8<\/span><span class=\"z-string\"> urls-3.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=7<\/span><span class=\"z-string\"> urls-3.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- Last few GCs ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253130:0x5566636cdbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     1621 ms: Scavenge 6.0 (<\/span><span class=\"z-entity z-name z-function\">8.8<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 4.8 (<\/span><span class=\"z-entity z-name z-function\">8.8<\/span><span class=\"z-source\">) MB, 1.45 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 1.000,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 1.000<\/span><span class=\"z-source\">) task<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253130:0x5566636cdbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-entity z-name z-function\">     1631<\/span><span class=\"z-string\"> ms:<\/span><span class=\"z-string\"> Mark-Compact<\/span><span class=\"z-constant z-numeric\"> 4.9<\/span><span class=\"z-source\"> (8.8<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 4.4 (<\/span><span class=\"z-entity z-name z-function\">9.0<\/span><span class=\"z-source\">) MB, 5.01 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.997,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.997<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> GC<\/span><span class=\"z-string\"> in<\/span><span class=\"z-string\"> old<\/span><span class=\"z-string\"> space<\/span><span class=\"z-string\"> requested<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253130:0x5566636cdbb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     1642 ms: Mark-Compact 7.3 (<\/span><span class=\"z-entity z-name z-function\">11.8<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 7.0 (<\/span><span class=\"z-entity z-name z-function\">11.8<\/span><span class=\"z-source\">) MB, 1.94 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.996,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.827<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> GC<\/span><span class=\"z-string\"> in<\/span><span class=\"z-string\"> old<\/span><span class=\"z-string\"> space<\/span><span class=\"z-string\"> requested<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- JS stacktrace ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">FATAL<\/span><span class=\"z-string\"> ERROR:<\/span><span class=\"z-string\"> Reached<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> limit<\/span><span class=\"z-string\"> Allocation<\/span><span class=\"z-string\"> failed<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> JavaScript<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> out<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> memory<\/span><\/span><\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0432\u044b\u0448\u0435, \u043a\u043e\u0434 \u0441\u0442\u0430\u043b \u043f\u0430\u0434\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0438 \u0432 7 \u041c\u0411 \u2014 \u043c\u044b \u0432\u044b\u0438\u0433\u0440\u0430\u043b\u0438 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 2 \u041c\u0411!<\/p>\n<p>\u041f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u043c\u044f\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435, \u0435\u0441\u043b\u0438 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u043f\u0440\u043e \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a \u2014 <code>TwoByte<\/code> \u0438 <code>OneByte<\/code>. \u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u0425\u0430\u0431\u0440, \u043a\u0430\u043a \u0438 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435, \u043e\u0442\u0434\u0430\u0435\u0442 \u0441\u0432\u043e\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0435 UTF-8:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> urls-4.js<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> main<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  ]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> pageUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">pageUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">arrayBuffer<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> &lt;---<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Buffer<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">from<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">html<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toString<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">ascii<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> &lt;---<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u043d\u0430\u0448\u0430 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043a\u0430 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0431\u0430\u0439\u0442\u043e\u0432 UTF-8<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-source\"> html<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">matchAll<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string z-begin\">\/<\/span><span class=\"z-string\">href=&quot;<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">(<\/span><span class=\"z-constant z-other z-character-class z-regexp\">.<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">*<\/span><span class=\"z-keyword z-operator z-quantifier z-regexp\">?<\/span><span class=\"z-punctuation z-definition z-group z-regexp\">)<\/span><span class=\"z-string\">&quot;<\/span><span class=\"z-punctuation z-definition z-string z-end\">\/<\/span><span class=\"z-keyword\">g<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> match<\/span><span class=\"z-source\">[<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u043d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439, \u0435\u0441\u043b\u0438 \u0432 \u0430\u0434\u0440\u0435\u0441\u0430\u0445 \u0431\u044b\u043b\u0438 \u043d\u0435-ASCII \u0441\u0438\u043c\u0432\u043e\u043b\u044b<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      linkUrl<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Buffer<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">from<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">ascii<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toString<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">utf-8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      linkUrls<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    html<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrl<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> linkUrls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">linkUrl<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">main<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0412\u044b\u0438\u0433\u0440\u0430\u043b\u0438 \u0435\u0449\u0435 \u043e\u043a\u043e\u043b\u043e 1 \u041c\u0411:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=7<\/span><span class=\"z-string\"> urls-4.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442!<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=6<\/span><span class=\"z-string\"> urls-4.js<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-string\"> \/dev\/null<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- Last few GCs ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253789:0x563785444bb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     1749 ms: Mark-Compact 4.9 (<\/span><span class=\"z-entity z-name z-function\">9.3<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 4.4 (<\/span><span class=\"z-entity z-name z-function\">9.5<\/span><span class=\"z-source\">) MB, 2.12 \/ 0.00 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.996,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.831<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> GC<\/span><span class=\"z-string\"> in<\/span><span class=\"z-string\"> old<\/span><span class=\"z-string\"> space<\/span><span class=\"z-string\"> requested<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">[<\/span><span class=\"z-source\">253789:0x563785444bb0<\/span><span class=\"z-punctuation\">]<\/span><span class=\"z-source\">     2530 ms: Mark-Compact 7.5 (<\/span><span class=\"z-entity z-name z-function\">10.1<\/span><span class=\"z-source\">) -<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> 5.5 (<\/span><span class=\"z-entity z-name z-function\">10.3<\/span><span class=\"z-source\">) MB, 5.66 \/ 0.01 ms  (<\/span><span class=\"z-entity z-name z-function\">average<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-string\"> 0.994,<\/span><span class=\"z-string\"> current<\/span><span class=\"z-string\"> mu<\/span><span class=\"z-string\"> =<\/span><span class=\"z-constant z-numeric\"> 0.993<\/span><span class=\"z-source\">) allocation failure<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-entity z-name z-function\"> scavenge<\/span><span class=\"z-string\"> might<\/span><span class=\"z-string\"> not<\/span><span class=\"z-string\"> succeed<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\">--- JS stacktrace ---<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">FATAL<\/span><span class=\"z-string\"> ERROR:<\/span><span class=\"z-string\"> Reached<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> limit<\/span><span class=\"z-string\"> Allocation<\/span><span class=\"z-string\"> failed<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> JavaScript<\/span><span class=\"z-string\"> heap<\/span><span class=\"z-string\"> out<\/span><span class=\"z-string\"> of<\/span><span class=\"z-string\"> memory<\/span><\/span><\/code><\/pre><h2 id=\"chto-v-itoge\"><a class=\"anchor\" href=\"#chto-v-itoge\" title=\"link to section\">#<\/a>\u0427\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435?<\/h2>\n<p>\u0414\u0432\u0438\u0436\u043e\u043a V8, \u043a\u0430\u043a \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u044b \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f JavaScript, \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0439 \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0440\u0430\u0431\u043e\u0442\u044b. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0435\u0433\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a. \u041d\u0430\u043c\u0435\u0440\u0435\u043d\u043d\u043e \u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445, \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u2014 \u0445\u043e\u0442\u044c \u043c\u044b \u0438 \"\u043e\u0431\u043e\u0433\u043d\u0430\u043b\u0438\" C++ \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u043d\u0435\u0447\u0435\u0441\u0442\u043d\u043e\u043c \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0435. \u041d\u043e, \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0437\u043d\u0430\u043d\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0441\u0442\u0440\u043e\u043a \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u043e\u0442\u043b\u043e\u0432\u0438\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/mrdoob\/three.js\/issues\/9679\">\u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u044b\u0435<\/a> \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u043a\u043e\u0434\u0430.<\/p>\n"},{"title":"\u042f\u0432\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438: \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0444\u0438\u0447\u0443 JavaScript \u0438 TypeScript","published":"2023-07-25T00:00:00+00:00","updated":"2023-07-25T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/js-explicit-resource-management-ru\/"}},"id":"https:\/\/iliazeus.lol\/articles\/js-explicit-resource-management-ru\/","content":"<p>\u041e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u0433\u0440\u044f\u0434\u0443\u0449\u0438\u0445 \u043d\u043e\u0432\u0438\u043d\u043e\u043a JavaScript \u0438 TypeScript \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/tc39\/proposal-explicit-resource-management\">\u044f\u0432\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438<\/a>. \u041d\u043e\u0432\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 <code>using foobar = ...<\/code> \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0438\u0434\u0438\u043e\u043c\u0443 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B5%D1%81%D1%83%D1%80%D1%81%D0%B0_%D0%B5%D1%81%D1%82%D1%8C_%D0%B8%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F\">RAII<\/a>, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u0435\u0435 \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043a\u043e\u0434, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u0430\u043a\u0438\u043c\u0438-\u043b\u0438\u0431\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438.<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/js-explicit-resource-management-ru\/cover.png\" alt=\"\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430\" \/><\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u044d\u0442\u0443 \u0444\u0438\u0447\u0443 \u2014 \u0432 \u0442\u043e\u043c \u0432\u0438\u0434\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043d\u0430 \u0441\u0435\u0439\u0447\u0430\u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0432 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-2-beta\/#using-declarations-and-explicit-resource-management\">TypeScript 5.2.0-beta<\/a> \u0441 \u043f\u043e\u043b\u0438\u0444\u0438\u043b\u043b\u043e\u043c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/disposablestack\">disposablestack<\/a>. \u042f \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u044e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, <code>DisposableStack<\/code>\/<code>AsyncDisposableStack<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e\u0433\u043e \u0431\u0430\u0433\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043f\u0430\u043b\u0441\u044f \u044f \u0441\u0430\u043c. \u041f\u043e \u043f\u0443\u0442\u0438 \u044f \u0442\u0430\u043a\u0436\u0435 \u043a\u043e\u0441\u043d\u0443\u0441\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u043d\u043e\u0432\u043e\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0439 Node.js, \u043f\u0440\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0435\u0449\u0435 \u0437\u043d\u0430\u044e\u0442 \u043d\u0435 \u0432\u0441\u0435.<\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/js-disposable-demo\">\u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>.<\/p>\n<h2 id=\"chto-nam-ponadobitsia-dlia-novykh-fich\"><a class=\"anchor\" href=\"#chto-nam-ponadobitsia-dlia-novykh-fich\" title=\"link to section\">#<\/a>\u0427\u0442\u043e \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u043e\u0432\u044b\u0445 \u0444\u0438\u0447<\/h2>\n<p>\u042f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e Node.js:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-version<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">v20.3.1<\/span><\/span><\/code><\/pre>\n<p>\u041d\u043e \u0432\u0441\u0435 \u0444\u0438\u0447\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0438 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 LTS-\u0432\u0435\u0440\u0441\u0438\u0438 Node 18.16.1.<\/p>\n<p>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0431\u0435\u0442\u0430-\u0432\u0435\u0440\u0441\u0438\u044e TypeScript, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u043b\u0438\u0444\u0438\u043b\u043b\u044b \u0434\u043b\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u0447\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u043f\u043e\u0437\u0430\u043b\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> i<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">D<\/span><span class=\"z-string\"> typescript@5.2-beta<\/span><span class=\"z-string\"> @types\/node@18<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> i<\/span><span class=\"z-string\"> disposablestack<\/span><\/span><\/code><\/pre><details><summary>\u041f\u043e\u043b\u043d\u044b\u0439 package.json<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> package.json<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">private<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">: <\/span><span class=\"z-constant z-language z-boolean\">true<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">type<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">module<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">scripts<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">demo<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">xargs npm start -- -o .\/cat.html &lt; .\/urls.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">start<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">tsc &amp;&amp; node --max-old-space-size=8 .\/dist\/main.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">tsc &amp;&amp; node --test .\/dist<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">start:incorrect<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">tsc &amp;&amp; node --max-old-space-size=8 .\/dist\/main-incorrect.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">demo:incorrect<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">xargs npm run start:incorrect -- -o .\/cat.html &lt; .\/urls.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">engines<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">node<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">&gt;=18.16.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">devDependencies<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">@types\/node<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">^18.16.19<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">typescript<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">^5.2.0-beta<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">dependencies<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">disposablestack<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">^1.1.0<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c IDE \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430 \u0442\u043e\u0436\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043b\u0430 \u043d\u043e\u0432\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441. \u042f \u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0441\u044c Visual Studio Code; \u0434\u043b\u044f \u043d\u0435\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0443\u0442\u044c \u043a \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0443, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442\u0442\u0435\u0440 \u043a\u043e\u0434\u0430 \u2014 <code>prettier<\/code> \u0435\u0449\u0435 \u043d\u0435 \u043f\u0435\u0440\u0435\u0432\u0430\u0440\u0438\u0432\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> .vscode\/settings.json<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">typescript.tsdk<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">: <\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">node_modules\/typescript\/lib<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">[typescript]<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">editor.defaultFormatter<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">vscode.typescript-language-features<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u0430\u043c \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440. \u0414\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 \u043d\u0443\u0436\u043d\u044b \u043e\u043f\u0446\u0438\u0438 <code>\"lib\": \"esnext\"<\/code> \u0438\u043b\u0438 <code>\"lib\": \"esnext.disposable\"<\/code>. \u042f \u0442\u0430\u043a\u0436\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u044e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 ES-\u043c\u043e\u0434\u0443\u043b\u0435\u0439.<\/p>\n<details>\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 tsconfig.json<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> tsconfig.json<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">  &quot;<\/span><span class=\"z-string\">compilerOptions<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">target<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">es2022<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">lib<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-source\"> [<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">esnext<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">dom<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">module<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">nodenext<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">rootDir<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/src<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">outDir<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/dist<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-string\">    &quot;<\/span><span class=\"z-string\">skipLibCheck<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<h2 id=\"sinkhronnye-resursy-podpiski-na-sobytiia\"><a class=\"anchor\" href=\"#sinkhronnye-resursy-podpiski-na-sobytiia\" title=\"link to section\">#<\/a>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b: \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/h2>\n<p>\u0421\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0441\u0443\u0440\u0441\u0430, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0432 JavaScript \u0438 TypeScript \u043d\u0443\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u2014 \u044d\u0442\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0435\u0435, \u043e\u0442 \u043d\u0438\u0445 \u0432\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043d\u0443\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u043e\u0442\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f. \u0412 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0438-\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0435\u0441\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442-\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a, \u0430 \u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0435\u0441\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u0447\u0442\u043e \u043f\u043e\u0440\u043e\u0436\u0434\u0430\u0435\u0442 \u0446\u0438\u043a\u043b \u0438\u0437 \u0441\u0441\u044b\u043b\u043e\u043a \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432 \u043a\u0443\u0447\u0435. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0440\u043e\u0436\u0434\u0430\u0442\u044c \u043d\u0435\u044f\u0432\u043d\u044b\u0435 \"\u0432\u0438\u0441\u044f\u0449\u0438\u0435\" \u0441\u0441\u044b\u043b\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0434\u0430\u0434\u0443\u0442 GC \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u044d\u0442\u0443 \u043f\u0430\u043c\u044f\u0442\u044c:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> listener<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> SomeListener<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> emitter<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> HeavyObject<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">emitter<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">on<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> listener<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">onEvent<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">emitter<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/*<\/span><span class=\"z-comment\"> ... <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">emitter<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> emitter \u043d\u0435 \u0441\u043e\u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u0436\u0438\u0432 listener<\/span><\/span><\/code><\/pre>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438. \u0412\u043e\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430-\u0440\u0435\u0441\u0443\u0440\u0441\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/event-subscription.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">disposablestack\/auto<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> EventEmitter<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:events<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">obj<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> EventEmitter<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> e<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-function\"> fn<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-keyword z-operator\">...<\/span><span class=\"z-variable z-parameter\">args<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Disposable<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">on<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">e<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> fn<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">Symbol<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">dispose<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">off<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">e<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> fn<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443 <code>Disposable<\/code> \u2014 \u0438\u043c\u0435\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>[Symbol.dispose]<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432.<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442 \u0434\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>subscribe()<\/code>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u0438\u0437 \u043d\u0435\u0434\u0430\u0432\u043d\u0438\u0445 \u0444\u0438\u0447 Node.js \u2014 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0443\u044e <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/nodejs.org\/dist\/latest-v20.x\/docs\/api\/test.html\">\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432<\/a>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/event-subscription.test.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> subscribe<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/event-subscription.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-variable z-other z-readwrite\"> assert<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:assert\/strict<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> EventEmitter<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:events<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> describe<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> it<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">describe<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event-subscription<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  it<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">is disposed at scope exit<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> expectedEvents<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 3<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> actualEvents<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> obj<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> EventEmitter<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-entity z-name z-function\"> fn<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">e<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> actualEvents<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">e<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0440\u0435\u0441\u0443\u0440\u0441 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430 using<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      using<\/span><span class=\"z-variable z-other z-constant z-js\"> guard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">obj<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> fn<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u0440\u0435\u0441\u0443\u0440\u0441 \u0436\u0438\u0432\u0435\u0442 \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u043c\u044b \u043d\u0435 \u0432\u044b\u0439\u0434\u0435\u043c \u0438\u0437 \u043e\u0431\u043b\u0430\u0441\u0442\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 guard<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> e<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> expectedEvents<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\"> obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">emit<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> e<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u043a\u043e\u043d\u0435\u0446 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u0437\u0434\u0435\u0441\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f guard[Symbol.dispose]()<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">emit<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 123<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">deepEqual<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">actualEvents<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> expectedEvents<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">obj<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">listenerCount<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">event<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0412\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> test<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-function\"> grep<\/span><span class=\"z-string\"> event-subscription<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> Subtest: event-subscription<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">ok<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> event-subscription<\/span><\/span><\/code><\/pre><h2 id=\"asinkhronnye-resursy-otkrytye-faily\"><a class=\"anchor\" href=\"#asinkhronnye-resursy-otkrytye-faily\" title=\"link to section\">#<\/a>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b: \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0435 \u0444\u0430\u0439\u043b\u044b<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u043f\u0440\u043e \u0440\u0443\u0447\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 Node.js, \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0438\u043c\u0435\u044e\u0442 \u0432 \u0432\u0438\u0434\u0443 \u0442\u043e, \u0447\u0442\u043e \u044f \u043d\u0430\u0437\u043e\u0432\u0443 <em>\u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438<\/em>. \u042d\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0435 \u0444\u0430\u0439\u043b\u044b, \u0441\u043e\u043a\u0435\u0442\u044b, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u0442\u0435, \u0447\u0442\u043e \u0443\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u0442\u0430\u043a\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> resource<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Resource<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0440\u0435\u0441\u0443\u0440\u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">  resource<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> Resource<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">open<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u0435\u0441\u0443\u0440\u0441<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword\"> finally<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0435\u043c \u0440\u0435\u0441\u0443\u0440\u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  await<\/span><span class=\"z-source\"> resource<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">close<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u041a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b, \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d: \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c <code>finally<\/code>, \u0447\u0435\u0433\u043e \u0435\u0449\u0435 \u0445\u043e\u0442\u0435\u0442\u044c? \u041e\u0434\u043d\u0430\u043a\u043e \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0432\u043d\u043e\u0441\u0442\u044c \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0432\u0438\u0434\u043d\u0430, \u0435\u0441\u043b\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> resourceA<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> ResourceA<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">  resourceA<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> ResourceA<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">open<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> resourceB<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> ResourceB<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  try<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    resourceB<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> ResourceB<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">open<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">resourceA<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-keyword\"> finally<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    await<\/span><span class=\"z-source\"> resourceB<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">close<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-keyword\"> finally<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  await<\/span><span class=\"z-source\"> resourceA<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">close<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u041a \u0442\u043e\u043c\u0443 \u0436\u0435, \u043d\u0435\u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u043e, \u0447\u0442\u043e \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u0431\u043b\u043e\u043a\u043e\u0432 <code>try<\/code> \u0438 <code>finally<\/code> \u0440\u0430\u0437\u043d\u044b\u0435. \u041f\u043b\u044e\u0441, \u0435\u0441\u0442\u044c \u0438 \u043c\u0435\u0441\u0442\u043e \u0434\u043b\u044f \u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0445 \u0431\u0430\u0433\u043e\u0432: \u0432\u0441\u0435\u0433\u0434\u0430 \u043b\u0438 \u0432\u044b \u043f\u043e\u043c\u043d\u0438\u043b\u0438 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0432 <code>finally<\/code> \u043d\u0443\u0436\u0435\u043d \u0437\u043d\u0430\u043a <code>?<\/code>?<\/p>\n<p>\u041d\u043e\u0432\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 <code>using<\/code> \u0434\u0435\u043b\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u043c:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/file.test.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> openFile<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/file.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-variable z-other z-readwrite\"> assert<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:assert\/strict<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> describe<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> it<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">describe<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">file<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  it<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">is disposed at scope exit<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      await using<\/span><span class=\"z-variable z-other z-constant z-js\"> file<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">dist\/test.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">w<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      await<\/span><span class=\"z-source\"> file<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writeFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">utf-8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      await using<\/span><span class=\"z-variable z-other z-constant z-js\"> file<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">dist\/test.txt<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">r<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-keyword\">await<\/span><span class=\"z-source\"> file<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">readFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">utf-8<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c <code>await using file = await ...<\/code>. \u041f\u0435\u0440\u0432\u044b\u0439 <code>await<\/code> \u0437\u0434\u0435\u0441\u044c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432: \u043f\u0440\u0438 \u0432\u044b\u0445\u043e\u0434\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d <code>await file[Symbol.asyncDispose]()<\/code>. \u0412\u0442\u043e\u0440\u043e\u0439 \u2014 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e: \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0437\u043e\u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 <code>openFile()<\/code>.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0434\u043b\u044f \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430. \u0412 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 <code>fs.FileHandle<\/code>.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/file.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">disposablestack\/auto<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-constant z-language\"> *<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-variable z-other z-readwrite\"> fs<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:fs\/promises<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Writable<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:stream<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0442\u0438\u043f \u043d\u0430\u0448\u0435\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u2014 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 AsyncDisposable \u0438 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e fs.FileHandle<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> interface<\/span><span class=\"z-entity z-name z-type\"> DisposableFile<\/span><span class=\"z-storage z-modifier\"> extends<\/span><span class=\"z-entity z-name z-type\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-other z-inherited-class\">FileHandle<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-other z-inherited-class\"> AsyncDisposable<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0442\u0430\u043a\u0436\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u043f\u043e\u0437\u0436\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  writableWebStream<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">options<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-type\">CreateWriteStreamOptions<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> WritableStream<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">path<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-parameter\"> flags<\/span><span class=\"z-keyword z-operator\">?<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">DisposableFile<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> file<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">open<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">path<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> flags<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0440\u044f\u043c\u043e \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 file \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Object.assign<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-source\"> Object<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">assign<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">file<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    [<\/span><span class=\"z-source\">Symbol<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">asyncDispose<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> file<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">close<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    writableWebStream<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> fs<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-type\">CreateWriteStreamOptions<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-source\"> autoClose<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> false<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      Writable<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">toWeb<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">file<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">createWriteStream<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">options<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0430\u0448\u0438 \u0442\u0435\u0441\u0442\u044b:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> test<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-function\"> grep<\/span><span class=\"z-string\"> file<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> Subtest: file<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">ok<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> file<\/span><\/span><\/code><\/pre><h2 id=\"async-sync-m-iuteksy\"><a class=\"anchor\" href=\"#async-sync-m-iuteksy\" title=\"link to section\">#<\/a>\"async-sync\": \u043c\u044c\u044e\u0442\u0435\u043a\u0441\u044b<\/h2>\n<p>\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 <code>await using foo = await ...<\/code> \u043c\u043e\u0436\u0435\u0442 \u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u043e\u0447\u0435\u043d\u044c-\u0442\u043e \u043d\u0443\u0436\u043d\u044b\u043c \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u0435\u043c. \u041d\u043e \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0443\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u043b\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435.<\/p>\n<p>\u041a\u0430\u043a \u043f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u043d\u043e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043e\u0434\u0438\u043d \u0438\u0437 \u043c\u043e\u0438\u0445 \u043b\u044e\u0431\u0438\u043c\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 RAII \u2014 \u043c\u044c\u044e\u0442\u0435\u043a\u0441:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/mutex.test.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Mutex<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/mutex.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-variable z-other z-readwrite\"> assert<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:assert\/strict<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> describe<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> it<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> setTimeout<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-variable z-other z-readwrite\"> sleep<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:timers\/promises<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">describe<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">mutex-guard<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  it<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">is disposed at scope exit<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> mutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Mutex<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> value<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-entity z-name z-function\"> task<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\"> &lt;<\/span><span class=\"z-constant z-numeric\"> 5<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> i<\/span><span class=\"z-keyword z-operator\">++<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f - \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 - \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u0434\u0440\u0443\u0433\u0438\u043c \u043e\u0436\u0438\u0434\u0430\u044e\u0449\u0438\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        using<\/span><span class=\"z-variable z-other z-constant z-js\"> guard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> mutex<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">acquire<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 guard - \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0441\u0435\u043a\u0446\u0438\u044f<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        const<\/span><span class=\"z-variable z-other z-constant z-js\"> newValue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> value<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        await<\/span><span class=\"z-entity z-name z-function\"> sleep<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">100<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">        value<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> newValue<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> \u0437\u0430\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0441\u0442\u0440\u043e\u0447\u043a\u0443 using guard, \u0447\u0442\u043e\u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0433\u043e\u043d\u043a\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    await<\/span><span class=\"z-support z-class\"> Promise<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">all<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">[<\/span><span class=\"z-entity z-name z-function\">task<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-entity z-name z-function\"> task<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">]<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">value<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 10<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043d\u0430\u0448 <code>Mutex<\/code> \u043a\u0430\u043a \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0444\u0430\u0431\u0440\u0438\u043a\u0430 <code>Disposable<\/code>-\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/mutex.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">disposablestack\/auto<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> class<\/span><span class=\"z-entity z-name z-type\"> Mutex<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  #promise<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-support z-type\"> null<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  async<\/span><span class=\"z-entity z-name z-function\"> acquire<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-entity z-name z-type\">Disposable<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    while<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#promise<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#promise<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-entity z-name z-function\"> callback<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#promise<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-support z-class\"> Promise<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">cb<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-variable z-other z-readwrite\"> callback<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> cb<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      [<\/span><span class=\"z-source\">Symbol<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">dispose<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">        this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#promise<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-language z-null z-js\"> null<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">        callback<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0427\u0442\u043e \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438?<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> test<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-function\"> grep<\/span><span class=\"z-string\"> mutex<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> Subtest: mutex-guard<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">ok<\/span><span class=\"z-constant z-numeric\"> 3<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> mutex-guard<\/span><\/span><\/code><\/pre><h2 id=\"sync-async-ochered-zadach\"><a class=\"anchor\" href=\"#sync-async-ochered-zadach\" title=\"link to section\">#<\/a>\"sync-async\": \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0437\u0430\u0434\u0430\u0447<\/h2>\n<p>\u041a\u0430\u043a \u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0437\u0430\u0434\u0430\u0447:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/task-queue.test.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> TaskQueue<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/task-queue.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-variable z-other z-readwrite\"> assert<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:assert\/strict<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> describe<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> it<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:test<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> setTimeout<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-variable z-other z-readwrite\"> sleep<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:timers\/promises<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">describe<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">task-queue<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  it<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">is disposed at scope exit<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> runningTaskCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    let<\/span><span class=\"z-variable z-other z-readwrite\"> maxRunningTaskCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-entity z-name z-function\"> task<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      runningTaskCount<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      maxRunningTaskCount<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> Math<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">max<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">maxRunningTaskCount<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> runningTaskCount<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      await<\/span><span class=\"z-entity z-name z-function\"> sleep<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">100<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">      runningTaskCount<\/span><span class=\"z-keyword z-operator\"> -=<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      await using<\/span><span class=\"z-variable z-other z-constant z-js\"> queue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> TaskQueue<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-source\"> concurrency<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      queue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      queue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      queue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      queue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u0432 \u043a\u043e\u043d\u0446\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0437\u0430\u0434\u0430\u0447 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">runningTaskCount<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    assert<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">equal<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">maxRunningTaskCount<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u0415\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043e\u0434\u043d\u043e\u0439 \u0434\u0435\u0442\u0430\u043b\u0438, \u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u043e\u0437\u0436\u0435:<\/p>\n<details><summary>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/task-queue.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">disposablestack\/auto<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> EventEmitter<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> once<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:events<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> type<\/span><span class=\"z-entity z-name z-type\"> Task<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-type\"> class<\/span><span class=\"z-entity z-name z-type\"> TaskQueue<\/span><span class=\"z-storage z-modifier\"> extends<\/span><span class=\"z-entity z-other z-inherited-class\"> EventEmitter<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0441\u0435\u0439\u0447\u0430\u0441 \u044d\u0442\u043e \u0435\u0449\u0435 \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u043d\u043e \u044d\u0442\u043e \u043f\u043e\u043b\u0435 - \u043e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u0430\u044f \u0434\u0435\u0442\u0430\u043b\u044c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  readonly<\/span><span class=\"z-variable z-object z-property\"> resources<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> AsyncDisposableStack<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  #concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  #tasks<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Task<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">  #runningTaskCount<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  constructor<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-object z-property\"> concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-super\">    super<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#concurrency<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> options<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">concurrency<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">on<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">taskFinished<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">#runNextTask<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  push<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">task<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Task<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">#tasks<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">task<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">#runNextTask<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  #<\/span><span class=\"z-entity z-name z-function\">runNextTask<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#runningTaskCount<\/span><span class=\"z-keyword z-operator\"> &gt;=<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#concurrency<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    const<\/span><span class=\"z-variable z-other z-constant z-js\"> nextTask<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">#tasks<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">shift<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-variable z-other z-readwrite\">nextTask<\/span><span class=\"z-source\">)<\/span><span class=\"z-keyword\"> return<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">    this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#runningTaskCount<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    nextTask<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">      .<\/span><span class=\"z-entity z-name z-function\">catch<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">        this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">emit<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">error<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> error<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">finally<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">        this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#runningTaskCount<\/span><span class=\"z-keyword z-operator\"> -=<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-language z-this\">        this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">emit<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">taskFinished<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  async<\/span><span class=\"z-source\"> [<\/span><span class=\"z-source\">Symbol<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">asyncDispose<\/span><span class=\"z-source\">]<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    while<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">#tasks<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">length<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-keyword z-operator\"> ||<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">#runningTaskCount<\/span><span class=\"z-keyword z-operator\"> &gt;<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">      await<\/span><span class=\"z-entity z-name z-function\"> once<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-language z-this\">this<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">taskFinished<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">catch<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    await<\/span><span class=\"z-variable z-language z-this\"> this<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">resources<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">disposeAsync<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre><\/details>\n<p>\u041f\u0440\u043e\u0441\u0442\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> test<\/span><span class=\"z-keyword z-operator\"> |<\/span><span class=\"z-entity z-name z-function\"> grep<\/span><span class=\"z-string\"> queue<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">#<\/span><span class=\"z-comment\"> Subtest: task-queue<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">ok<\/span><span class=\"z-constant z-numeric\"> 4<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\"> task-queue<\/span><\/span><\/code><\/pre><h2 id=\"ispol-zuem-vse-vmeste-fetchcat\"><a class=\"anchor\" href=\"#ispol-zuem-vse-vmeste-fetchcat\" title=\"link to section\">#<\/a>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435: fetchCat<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>fetchCat()<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0447\u0435\u0442\u044b\u0440\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043d\u0430\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/fetch-cat.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> subscribe<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/event-subscription.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> openFile<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/file.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Mutex<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/mutex.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> TaskQueue<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/task-queue.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/**<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> * \u0417\u0430\u0431\u0440\u0430\u0442\u044c GET-\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043e \u0432\u0441\u0435\u0445 `urls` \u0438 \u0441\u043a\u043b\u0435\u0438\u0442\u044c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443 \u0432 \u0444\u0430\u0439\u043b `outPath`.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> * \u041f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0432 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043d\u0435 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> *<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> * <\/span><span class=\"z-punctuation\">@<\/span><span class=\"z-storage z-type\">param<\/span><span class=\"z-variable z-other z-jsdoc\"> options.concurrency<\/span><span class=\"z-comment\"> \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\"> * <\/span><span class=\"z-punctuation\">@<\/span><span class=\"z-storage z-type\">param<\/span><span class=\"z-variable z-other z-jsdoc\"> options.onError<\/span><span class=\"z-comment\"> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 urls<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\"> *\/<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> fetchCat<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    urls<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    outPath<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    onError<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-constant z-js\"> urls<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> concurrency<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> onError<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> options<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0434\u043b\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f concurrency \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e \u0437\u0430\u0434\u0430\u0447<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> taskQueue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> TaskQueue<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-other z-readwrite\"> concurrency<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0442\u043e\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0435\u0441\u0443\u0440\u0441<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  using<\/span><span class=\"z-variable z-other z-constant z-js\"> errorSubscription<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">taskQueue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">error<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> onError<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043c\u044c\u044e\u0442\u0435\u043a\u0441\u043e\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileMutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Mutex<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0444\u0430\u0439\u043b \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u0440\u044b\u0442 \u0432 \u043a\u043e\u043d\u0446\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFile<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">w<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> url<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> urls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 fetch() - \u0435\u0449\u0435 \u043e\u0434\u043d\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0435 \u043d\u043e\u0432\u043e\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435 Node.js<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">      \/\/<\/span><span class=\"z-comment\"> \u043f\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443 \u043e\u043d \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-variable z-other z-constant z-js\"> response<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">url<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileGuard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> outFileMutex<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">acquire<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">        \/\/<\/span><span class=\"z-comment\"> \u0430 \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0435 \u0436\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0441\u0442\u0440\u0438\u043c\u043e\u0432, \u0447\u0442\u043e \u0438 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        await<\/span><span class=\"z-source\"> response<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">body<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">pipeTo<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">outFile<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writableWebStream<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u041e\u043f\u0438\u0448\u0435\u043c \u0442\u043e\u0447\u043a\u0443 \u0432\u0445\u043e\u0434\u0430, \u0440\u0430\u0441\u043f\u0430\u0440\u0441\u0438\u0432 \u0430\u0433\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c \u0432 Node.js \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u043c \u2014 \u0435\u0449\u0435 \u043e\u0434\u043d\u0430 \u043d\u0435\u0434\u0430\u0432\u043d\u044f\u044f \u0444\u0438\u0447\u0430!<\/p>\n<details><summary>\u041a\u043e\u0434 main.ts<\/summary>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/main.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> parseArgs<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">node:util<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> fetchCat<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/fetch-cat.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-entity z-name z-function\"> explain<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Error<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> message<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">message<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">let<\/span><span class=\"z-variable z-other z-readwrite\"> e<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> error<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cause<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-entity z-name z-type\"> Error<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> e<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> e<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> e<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cause<\/span><span class=\"z-keyword\"> as<\/span><span class=\"z-entity z-name z-type\"> Error<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-other z-readwrite\">    message<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">: <\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-keyword z-operator\"> +<\/span><span class=\"z-source\"> e<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">message<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> message<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> args<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> parseArgs<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  strict<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  allowPositionals<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-constant z-language z-boolean\"> true<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  options<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    outPath<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">o<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      type<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    concurrency<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      short<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">j<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      type<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">string<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">      default<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &#39;<\/span><span class=\"z-string\">2<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">values<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">outPath<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">log<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-string\">missing required option: -o (--outPath)<\/span><span class=\"z-punctuation z-definition z-string\">&#39;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">exit<\/span><span class=\"z-source\">(<\/span><span class=\"z-constant z-numeric\">1<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">await<\/span><span class=\"z-entity z-name z-function\"> fetchCat<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  urls<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-source\"> args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">positionals<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  outPath<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-source\"> args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">values<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">outPath<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  concurrency<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-entity z-name z-function\"> Number<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">args<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">values<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">concurrency<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  onError<\/span><span class=\"z-punctuation z-separator z-key-value\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">e<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    console<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">error<\/span><span class=\"z-source\">(<\/span><span class=\"z-entity z-name z-function\">explain<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">e<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    process<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">exitCode<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre><\/details>\n<p>\u0417\u0430\u0434\u0430\u0434\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e URL \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>urls.txt<\/code>, \u043d\u0435 \u0437\u0430\u0431\u044b\u0432 \u043f\u0430\u0440\u043e\u0447\u043a\u0443 \u00ab\u043e\u0431\u043c\u0430\u043d\u043e\u043a\u00bb \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0432\u044b\u0432\u043e\u0434\u0430 \u043e\u0448\u0438\u0431\u043e\u043a:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/asdfasdfasdfasdf<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/144758\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/companies\/floor796\/articles\/673318\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/companies\/skyeng\/articles\/487764\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/177159\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/124899\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/149237\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/foobarfoobarfoobar<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/202304\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><span>https:\/\/habr.com\/ru\/articles\/307822\/comments\/<\/span><\/span><\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> run<\/span><span class=\"z-string\"> demo<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> demo<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> xargs npm run start -- -o .\/cat.html <\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\"> .\/urls.txt<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> start<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> tsc <\/span><span class=\"z-punctuation\">&amp;&amp;<\/span><span class=\"z-entity z-name z-function\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=8<\/span><span class=\"z-string\"> .\/dist\/main-incorrect.js<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">o<\/span><span class=\"z-string\"> .\/cat.html<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-string\"> https:\/\/asdfasdfasdfasdf<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/144758\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/floor796\/articles\/673318\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/skyeng\/articles\/487764\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/177159\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/124899\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/149237\/comments\/<\/span><span class=\"z-string\"> https:\/\/foobarfoobarfoobar<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/202304\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/307822\/comments\/<\/span><\/span><\/code><\/pre>\n<p>\u0425\u043c, \u0441\u0442\u0440\u0430\u043d\u043d\u043e. \u0421\u043a\u0440\u0438\u043f\u0442 \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f, \u0430 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043f\u0443\u0441\u0442\u043e\u0439. \u041f\u043e\u0445\u043e\u0436\u0435 \u043d\u0430 \u0431\u0430\u0433.<\/p>\n<h2 id=\"neochevidnyi-bag\"><a class=\"anchor\" href=\"#neochevidnyi-bag\" title=\"link to section\">#<\/a>\u041d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0439 \u0431\u0430\u0433<\/h2>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0439\u0442\u0438, \u0432 \u0447\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0430, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u043e\u0434 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/fetch-cat.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> subscribe<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/event-subscription.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> openFile<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/file.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Mutex<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/mutex.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> TaskQueue<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/task-queue.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> fetchCat<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    urls<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    outPath<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    onError<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-constant z-js\"> urls<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> concurrency<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> onError<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> options<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> taskQueue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> TaskQueue<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-other z-readwrite\"> concurrency<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  using<\/span><span class=\"z-variable z-other z-constant z-js\"> errorSubscription<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">taskQueue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">error<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> onError<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFile<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">w<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileMutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Mutex<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> url<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> urls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-variable z-other z-constant z-js\"> response<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">url<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileGuard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> outFileMutex<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">acquire<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        await<\/span><span class=\"z-source\"> response<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">body<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">pipeTo<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">outFile<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writableWebStream<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0417\u0434\u0435\u0441\u044c \u043a\u043e\u043d\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443 outFile \u0438 \u0443 taskQueue.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u041e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e outFile \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u0440\u044b\u0442 \u0440\u0430\u043d\u044c\u0448\u0435, \u0447\u0435\u043c taskQueue \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u0441\u044f!<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043d\u0435 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b. \u041e\u043d\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 <code>outFile<\/code> \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u043e \u043d\u0435 \u043a \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u0430 \u043a\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0436\u0438\u0437\u043d\u0438 \u0437\u0430\u0434\u0430\u0447 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438. \u0424\u0430\u0439\u043b \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0437\u0430\u043a\u0440\u044b\u0442 \u043d\u0435 \u0440\u0430\u043d\u044c\u0448\u0435, \u0447\u0435\u043c \u0432\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u0441\u044f.<\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, Node.js \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u044f\u043c \u043f\u0440\u043e\u0434\u043b\u0435\u0432\u0430\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 \u0437\u0430\u0445\u0432\u0430\u0447\u0435\u043d\u043d\u044b\u0445 \u0438\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432. \u041f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0438\u0445 \u044f\u0432\u043d\u043e. \u041d\u043e \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u2014 \u0434\u043b\u044f \u0430\u0433\u0433\u0440\u0435\u0440\u0430\u0446\u0438\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u043b\u0430\u0441\u0441 <code>AsyncDisposableStack<\/code> \u2014 \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u043e\u043f\u043e\u0437\u0430\u043b\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> src\/fetch-cat.ts<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> subscribe<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/event-subscription.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> openFile<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/file.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> Mutex<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/mutex.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">import<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-readwrite\"> TaskQueue<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword\"> from<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">.\/task-queue.js<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">export<\/span><span class=\"z-storage z-modifier\"> async<\/span><span class=\"z-storage z-type\"> function<\/span><span class=\"z-entity z-name z-function\"> fetchCat<\/span><span class=\"z-punctuation\">(<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-parameter\">  options<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    urls<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-meta z-type\">[<\/span><span class=\"z-meta z-type\">]<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    outPath<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> string<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-variable z-object z-property\">    concurrency<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> number<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    onError<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-variable z-parameter\">error<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-support z-type z-primitive\"> any<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-support z-type z-primitive\"> void<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\">:<\/span><span class=\"z-entity z-name z-type\"> Promise<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&lt;<\/span><span class=\"z-support z-type z-primitive\">void<\/span><span class=\"z-punctuation z-definition z-typeparameters\">&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-punctuation\"> {<\/span><span class=\"z-variable z-other z-constant z-js\"> urls<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> concurrency<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-constant z-js\"> onError<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-other z-readwrite\"> options<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  await using<\/span><span class=\"z-variable z-other z-constant z-js\"> taskQueue<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> TaskQueue<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation\">{<\/span><span class=\"z-variable z-other z-readwrite\"> concurrency<\/span><span class=\"z-punctuation\"> }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u041f\u043e\u043b\u0435 taskQueue.resources \u0438\u043c\u0435\u0435\u0442 \u0442\u0438\u043f AsyncDisposableStack.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u041a\u0430\u043a \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 TaskQueue, \u043e\u043d\u043e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0435\u0433\u043e dispose,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u0440\u0438\u0447\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0437\u0430\u0434\u0430\u0447.<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> errorSubscription<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-entity z-name z-function\"> subscribe<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">taskQueue<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">error<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-variable z-other z-readwrite\"> onError<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">resources<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">use<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">errorSubscription<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> outFile<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> openFile<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">outPath<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">w<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">resources<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">use<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">outFile<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-punctuation z-definition z-comment\"> \/\/<\/span><span class=\"z-comment\"> \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  const<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileMutex<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword z-operator z-new\"> new<\/span><span class=\"z-entity z-name z-function\"> Mutex<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-storage z-type\">const<\/span><span class=\"z-variable z-other z-constant z-js\"> url<\/span><span class=\"z-keyword z-operator z-expression z-of z-js\"> of<\/span><span class=\"z-variable z-other z-readwrite\"> urls<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    taskQueue<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">push<\/span><span class=\"z-source\">(<\/span><span class=\"z-storage z-modifier\">async<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">      const<\/span><span class=\"z-variable z-other z-constant z-js\"> response<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-entity z-name z-function\"> fetch<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-other z-readwrite\">url<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">        using<\/span><span class=\"z-variable z-other z-constant z-js\"> outFileGuard<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-keyword\"> await<\/span><span class=\"z-source\"> outFileMutex<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">acquire<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        await<\/span><span class=\"z-source\"> response<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">body<\/span><span class=\"z-punctuation z-accessor\">?.<\/span><span class=\"z-entity z-name z-function\">pipeTo<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">outFile<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">writableWebStream<\/span><span class=\"z-source\">(<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    }<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u041a \u044d\u0442\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c taskQueue.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u041f\u0440\u0438 \u0435\u0433\u043e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u0432\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0430 \u043f\u043e\u0442\u043e\u043c \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d \u0432\u0435\u0441\u044c \u0441\u0442\u0435\u043a taskQueue.resources.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0444\u0430\u0439\u043b \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0437\u0430\u043a\u0440\u044b\u0442<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043b\u0438 \u0443 \u043d\u0430\u0441 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0434\u0435\u043b\u043e:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"shellscript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$<\/span><span class=\"z-string\"> npm<\/span><span class=\"z-string\"> run<\/span><span class=\"z-string\"> demo<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> demo<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> xargs npm start -- -o .\/cat.html <\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\"> .\/urls.txt<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> start<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> tsc <\/span><span class=\"z-punctuation\">&amp;&amp;<\/span><span class=\"z-entity z-name z-function\"> node<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">-max-old-space-size=8<\/span><span class=\"z-string\"> .\/dist\/main.js<\/span><span class=\"z-string\"> -<\/span><span class=\"z-string\">o<\/span><span class=\"z-string\"> .\/cat.html<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/ruvds\/articles\/346442\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/203048\/comments\/<\/span><span class=\"z-string\"> https:\/\/asdfasdfasdfasdf<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/144758\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/floor796\/articles\/673318\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/companies\/skyeng\/articles\/487764\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/177159\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/124899\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/149237\/comments\/<\/span><span class=\"z-string\"> https:\/\/foobarfoobarfoobar<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/202304\/comments\/<\/span><span class=\"z-string\"> https:\/\/habr.com\/ru\/articles\/307822\/comments\/<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">fetch<\/span><span class=\"z-string\"> failed:<\/span><span class=\"z-string\"> getaddrinfo<\/span><span class=\"z-string\"> ENOTFOUND<\/span><span class=\"z-string\"> asdfasdfasdfasdf<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">fetch<\/span><span class=\"z-string\"> failed:<\/span><span class=\"z-string\"> getaddrinfo<\/span><span class=\"z-string\"> ENOTFOUND<\/span><span class=\"z-string\"> foobarfoobarfoobar<\/span><\/span><\/code><\/pre>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e! \u0412\u0441\u0435 (\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435) \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0431\u044b\u043b\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b, \u0430 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0432 \u0432 <code>.\/cat.html<\/code>, \u043c\u043e\u0436\u0435\u043c \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0438 \u0431\u0435\u0437 \u0433\u043e\u043d\u043e\u043a.<\/p>\n<p>\u041a\u043b\u0430\u0441\u0441\u044b <code>DisposableStack<\/code> \u0438 <code>AsyncDisposableStack<\/code> \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0434\u043b\u044f \u0430\u0433\u0433\u0440\u0435\u0433\u0430\u0446\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432 \u043e\u0434\u0438\u043d. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043b\u044e\u0431\u043e\u0439 <code>Disposable<\/code>-\u0440\u0435\u0441\u0443\u0440\u0441, \u0435\u0441\u043b\u0438 \u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u043f\u043e\u0434-\u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0441\u0432\u043e\u0439 <code>DisposableStack<\/code>, \u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0442\u044c \u0435\u0433\u043e \u0443 \u0441\u0435\u0431\u044f \u0432 <code>dispose()<\/code>. \u0421 <code>AsyncDisposable<\/code> \u0438 <code>AsyncDisposableStack<\/code> \u2014 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e.<\/p>\n<h2 id=\"article-symbol-dispose\"><a class=\"anchor\" href=\"#article-symbol-dispose\" title=\"link to section\">#<\/a><code>article[Symbol.dispose]()<\/code><\/h2>\n<p>\u0418\u0434\u0435\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 \u0434\u043b\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 RAII \u043d\u0435 \u043d\u043e\u0432\u0430 \u2014 \u043e\u043d \u0435\u0441\u0442\u044c \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/proposals\/csharp-8.0\/using#using-declaration\">\u0432 C#<\/a> \u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/docs.python.org\/3\/reference\/compound_stmts.html#the-with-statement\">\u0432 Python<\/a>. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u0437 \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 JavaScript \u0438 TypeScript. \u0423 \u043d\u0435\u0435 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0438 \u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b. \u041d\u043e, \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043d\u0438\u0445, \u044f \u043e\u0447\u0435\u043d\u044c \u0440\u0430\u0434 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044e \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 \u2014 \u0438, \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0441\u043c\u043e\u0433 \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c, \u043f\u043e\u0447\u0435\u043c\u0443.<\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/iliazeus\/js-disposable-demo\">\u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>.<\/p>\n"},{"title":"\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u0435\u0440\u0435\u0432\u0430 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432. \u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0425\u0430\u0431\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u044b Reddit; \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u044b\u0432\u0430\u0435\u043c \u0425\u0430\u0431\u0440","published":"2023-04-19T00:00:00+00:00","updated":"2023-04-19T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/"}},"id":"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/","content":"<p>\u042f \u043b\u044e\u0431\u043b\u044e \u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u044b\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438. \u0414\u043b\u044f \u043d\u0438\u0445 \u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043b\u0443\u0447\u0448\u0443\u044e \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0443. \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0444\u043e\u0440\u0443\u043c\u043e\u0432 \u0438\u0437 \u0434\u0432\u0443\u0445\u0442\u044b\u0441\u044f\u0447\u043d\u044b\u0445 \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u0434\u0432\u0430-\u0442\u0440\u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u043b\u0438\u043d\u0435\u0439\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440\u0430 \u0431\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u043e\u043c\u0443 \u043a\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442. \u0410 \u0438\u043c\u0438\u0434\u0436\u0431\u043e\u0440\u0434\u044b \u043c\u043d\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u043d\u0430 \u043f\u043e\u043b\u043d\u043e\u043c \u0441\u0435\u0440\u044c\u0435\u0437\u0435 \u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0447\u0438\u0442\u0430\u0442\u044c.<\/p>\n<p>\u041e\u0434\u043d\u0430 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0441\u0442\u0430\u0440\u044b\u0445 \u0438 \u0441\u0430\u043c\u044b\u0445 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043f\u043b\u043e\u0449\u0430\u0434\u043e\u043a \u0441 \u0434\u0435\u0440\u0435\u0432\u044c\u044f\u043c\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432 \u2014 \u044d\u0442\u043e Reddit. \u041f\u0440\u0430\u0432\u0434\u0430, \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0435\u0434\u0438\u043d\u0430 \u0432 \u043e\u0434\u043d\u043e\u043c: \u0435\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0443\u0436\u0430\u0441\u0435\u043d. \u041d\u043e \u0435\u0433\u043e API \u043e\u0442\u043a\u0440\u044b\u0442\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430 \u0432\u044b\u0431\u043e\u0440 \u0435\u0441\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043e\u0432 \u2014 \u043d\u0430 \u041a\u0414\u041f\u0412 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/play.google.com\/store\/apps\/details?id=o.o.joey\">Joey<\/a>, <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/play.google.com\/store\/apps\/details?id=reddit.news\">Relay<\/a>, <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/play.google.com\/store\/apps\/details?id=me.ccrama.slideforreddittabletuiunlock\">Slide<\/a> \u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/play.google.com\/store\/apps\/details?id=com.rubenmayayo.reddit\">Boost<\/a>, \u0430 \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435. \u0418\u0445 \u0430\u0432\u0442\u043e\u0440\u044b \u2014 \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0438 \u0441\u0430\u043c\u0438 \u043d\u0435\u0434\u043e\u0432\u043e\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u0420\u0435\u0434\u0434\u0438\u0442\u0430 \u2014 \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438 \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u0441\u0438\u043b \u043d\u0430 \u043f\u043e\u0438\u0441\u043a \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432. \u0418 \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0438\u0445 \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u0438\u0448\u043b\u0430 \u043a \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0438\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u043c \u0434\u0438\u0437\u0430\u0439\u043d\u0430.<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/cover.png\" alt=\"\u0421\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e \u2014 Joey, Relay, Slide, Boost\" \/><\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c, \u0447\u0435\u043c \u043c\u043d\u0435 \u0442\u0430\u043a \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0434\u0438\u0437\u0430\u0439\u043d \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432, \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0435\u0433\u043e \u0441 \u0434\u0435\u0440\u0435\u0432\u044c\u044f\u043c\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432 \u0425\u0430\u0431\u0440\u0430, \u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0444\u0430\u043d\u0442\u0430\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0431\u044b \u043c\u043e\u0433\u043b\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u044b \u0425\u0430\u0431\u0440\u0430 \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f Reddit.<\/p>\n<h2 id=\"osnovy\"><a class=\"anchor\" href=\"#osnovy\" title=\"link to section\">#<\/a>\u041e\u0441\u043d\u043e\u0432\u044b<\/h2>\n<p>\u041a\u0430\u043a\u043e\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u044f \u043d\u0430\u0437\u044b\u0432\u0430\u044e \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \"\u0434\u0435\u0440\u0435\u0432\u043e\u043c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432\"?<\/p>\n<ul>\n<li>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f \u0435\u0441\u0442\u044c \u043d\u0435 \u0431\u043e\u043b\u0435\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0434\u0440\u0443\u0433\u043e\u0433\u043e, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u043d \u0441\u0432\u044f\u0437\u0430\u043d \u043a\u0430\u043a \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u0434\u0438\u0430\u043b\u043e\u0433\u0430.<\/p>\n<p>\u0411\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u043c, \u0430 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439-\u043e\u0442\u0432\u0435\u0442 \u2014 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c. \u0421\u0442\u0440\u043e\u0433\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u044d\u0442\u043e \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0442\u0432\u0435\u0442. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f \u0442\u043e\u0433\u043e \u0436\u0435 \u0430\u0432\u0442\u043e\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u044b \"\u043d\u0438\u0436\u0435\" \u0432 \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435, \u0447\u0435\u043c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435.<\/p>\n<p>\u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u044d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0442\u0441\u0442\u0443\u043f\u0430\u043c\u0438 \u0441\u043b\u0435\u0432\u0430, \u043d\u043e \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u044b. \u0418\u0437-\u0437\u0430 \u043d\u0435\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044f \u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u0443 \u044f \u043d\u0435 \u043d\u0430\u0437\u044b\u0432\u0430\u044e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u044b \u0432 \u0442\u0432\u0438\u0442\u0442\u0435\u0440\u0435 \u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u044b\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043a\u0430\u043a \u0440\u0430\u0437 \u0442\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c. \u0421\u043b\u0435\u0432\u0430 \u2014 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435, \u0441\u043f\u0440\u0430\u0432\u0430 \u2014 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0420\u0435\u0434\u0434\u0438\u0442\u0430 (<a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/play.google.com\/store\/apps\/details?id=com.rubenmayayo.reddit\">Boost<\/a>).<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/overview.png\" alt=\"\u0421\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0445 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u043e\u0432 \u0441 \u0425\u0430\u0431\u0440\u0430 \u0438 Boost\" \/><\/p>\n<p>\u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0438\u0445 \u043f\u043e \u043a\u043e\u0441\u0442\u043e\u0447\u043a\u0430\u043c.<\/p>\n<h2 id=\"otstupy\"><a class=\"anchor\" href=\"#otstupy\" title=\"link to section\">#<\/a>\u041e\u0442\u0441\u0442\u0443\u043f\u044b<\/h2>\n<p>\u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u043a\u0430\u043a \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432. \u041d\u0430 \u0425\u0430\u0431\u0440\u0435 \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u0441\u043b\u0435\u0432\u0430, \u043f\u043b\u044e\u0441 \u0442\u043e\u0447\u043a\u0438 \u043f\u043e \u0447\u0438\u0441\u043b\u0443 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 (\u0434\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0430):<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/margin.png\" alt=\"\u041e\u0442\u0441\u0442\u0443\u043f\u044b \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u0438 \u0432 Boost\" \/><\/p>\n<p>\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0432 Boost \u0442\u043e\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043e\u0442\u0441\u0442\u0443\u043f\u044b, \u043d\u043e \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044c\u0448\u0438\u0435. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0434\u043b\u044f, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0442\u0435\u043a\u0441\u0442\u0430. \u0423 Boost \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u043f\u043e\u0442\u043e\u043b\u043e\u043a \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u043e\u0442\u0441\u0442\u0443\u043f\u043e\u0432 \u2014 \u043f\u0440\u0430\u0432\u0434\u0430, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043e\u043d \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435. \u041d\u043e \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u0442\u0430\u043a\u043e\u0439 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0442\u0435\u043a\u0441\u0442 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0432\u0441\u0435 \u0435\u0449\u0435 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043c\u0435\u0441\u0442\u0430.<\/p>\n<p>\u041a\u0430\u043a \u0431\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b \u0425\u0430\u0431\u0440 \u0441 \u0442\u0430\u043a\u0438\u043c\u0438 \u043e\u0442\u0441\u0442\u0443\u043f\u0430\u043c\u0438? \u041d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435 \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0442\u0438\u043b\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0432\u0430\u0442\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b DevTools \u0432 Firefox, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c. \u0412\u043a\u043b\u044e\u0447\u0438\u043b Responsive Design Mode \u0441 \u043f\u0440\u0435\u0441\u0435\u0442\u043e\u043c <code>Galaxy S10\/S10+ Android 11<\/code> \u0438 \u043d\u0430\u0431\u0440\u0430\u043b \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__comment &gt; *<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">margin-left: 0;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">position: unset; margin-left: 5px;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__breadcrumbs<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">display: none;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span><\/code><\/pre>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/margin-habr-before-after.png\" alt=\"\u041e\u0442\u0441\u0442\u0443\u043f\u044b \u043d\u0430 \u0425\u0430\u0431\u0440\u0435: \u0434\u043e \u0438 \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0441\u0442\u044b\u043b\u044f\" \/><\/p>\n<p>\u0421\u0440\u0430\u0437\u0443 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u043e\u0434\u0438\u043d \u044d\u043a\u0440\u0430\u043d \u0432\u043b\u0435\u0437\u0430\u044e\u0442 \u043d\u0435 \u0434\u0432\u0430 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f, \u0430 \u0443\u0436\u0435 \u0442\u0440\u0438. \u0418 \u043e\u043d\u0438 \u043d\u0435 \u044e\u0442\u044f\u0442\u0441\u044f \u043d\u0430 \u043f\u0440\u0430\u0432\u043e\u0439 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0435 \u044d\u043a\u0440\u0430\u043d\u0430. \u041d\u043e \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0445\u0443\u0436\u0435 \u0441\u0442\u0430\u043b\u0430 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u044c. \u041a\u0430\u043a \u0441 \u044d\u0442\u0438\u043c \u0431\u043e\u0440\u0435\u0442\u0441\u044f Boost?<\/p>\n<h2 id=\"indikatory-vlozhennosti\"><a class=\"anchor\" href=\"#indikatory-vlozhennosti\" title=\"link to section\">#<\/a>\u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/h2>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0449\u0435 \u0440\u0430\u0437 \u043d\u0430 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0432 \u043e\u0431\u043e\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445. \u0418 \u0442\u0430\u043c, \u0438 \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438: \u043a\u0440\u0443\u0436\u043e\u0447\u043a\u0438 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435, \u043f\u043e\u043b\u043e\u0441\u044b \u0432 Boost. \u041d\u043e \u043d\u0430 \u0425\u0430\u0431\u0440\u0435, \u043a\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u043e\u043d\u0438 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0445\u0443\u0436\u0435. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0440\u0430\u0432\u043d\u0438\u043c, \u0438 \u0434\u0430\u0436\u0435 \u0434\u0430\u0434\u0438\u043c \u0425\u0430\u0431\u0440\u0443 \u0444\u043e\u0440\u0443 \u2014 \u0443\u0431\u0435\u0440\u0435\u043c \u0432\u043b\u0438\u044f\u043d\u0438\u0435 \u0446\u0432\u0435\u0442\u0430:<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/depth-indicators-bw.png\" alt=\"\u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u043e\u0432 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u0438 \u0432 Boost, \u043e\u0431\u0435\u0441\u0446\u0432\u0435\u0447\u0435\u043d\u043e\" \/><\/p>\n<p>\u041a\u0440\u0443\u0436\u043e\u0447\u043a\u0438 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u044b \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0434\u0430\u043b\u0435\u043a\u043e \u043e\u0442 \u043a\u0440\u0443\u0436\u043e\u0447\u043a\u043e\u0432 \u0441\u043e\u0441\u0435\u0434\u043d\u0438\u0445 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432, \u0438 \u0438\u0445 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c. \u0412 \u0438\u0442\u043e\u0433\u0435, \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u043f\u043e \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u0431\u0435\u0440\u0443\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u043e\u0442\u0441\u0442\u0443\u043f\u044b. \u0414\u0443\u043c\u0430\u044e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0445 \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438.<\/p>\n<p>Boost \u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u043e\u0441\u044b \u043d\u0430 \u0432\u0441\u044e \u0432\u044b\u0441\u043e\u0442\u0443 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f. \u0418\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0432\u0435\u0440\u0445\u043d\u0438\u0435 \u0438 \u043d\u0438\u0436\u043d\u0438\u0435 \u043a\u043e\u043d\u0446\u044b \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u043e\u0441 \u043e\u0447\u0435\u043d\u044c \u0431\u043b\u0438\u0437\u043a\u043e \u043a \u0441\u043e\u0441\u0435\u0434\u043d\u0438\u043c, \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043b\u0435\u0433\u0447\u0435 \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0438\u0445 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u044c.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__comment<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> `<\/span><span class=\"z-string\">border-left: solid 5px grey; margin-left: -10px;<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__children<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">padding-top: 0;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">margin-bottom: 0;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__comment<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">padding-top: 10px; border-top: solid 1px grey;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span><\/code><\/pre>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c. \u0421\u043b\u0435\u0432\u0430 \u2014 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b, \u0432 \u0446\u0435\u043d\u0442\u0440\u0435 \u2014 \u0434\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0431\u043b\u043e\u043a\u0430 \u043a\u043e\u0434\u0430, \u0441\u043f\u0440\u0430\u0432\u0430 \u2014 \u043f\u043e\u0441\u043b\u0435.<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/border-left-habr-before-after.png\" alt=\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043d\u0430\u0448\u0438\u0445 \u043a\u043e\u0441\u0442\u044b\u043b\u0435\u0439\" \/><\/p>\n<h2 id=\"tsvet-kak-indikator-glubiny-vlozhennosti\"><a class=\"anchor\" href=\"#tsvet-kak-indikator-glubiny-vlozhennosti\" title=\"link to section\">#<\/a>\u0426\u0432\u0435\u0442 \u043a\u0430\u043a \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/h2>\n<p>\u0415\u0449\u0435 \u043e\u0434\u043d\u0438\u043c \u0432\u0430\u0436\u043d\u044b\u043c \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0432 Boost \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0446\u0432\u0435\u0442 \u043f\u043e\u043b\u043e\u0441\u044b \u0441\u043b\u0435\u0432\u0430. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u043f\u0440\u043e\u0441\u0442 \u2014 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u043d\u0430 \u0431\u043b\u0438\u0437\u043a\u0438\u0445, \u043d\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0443\u0440\u043e\u0432\u043d\u044f\u0445 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0446\u0432\u0435\u0442\u0430, \u043f\u0440\u0438\u0447\u0435\u043c \u0447\u0435\u043c \u0431\u043b\u0438\u0436\u0435 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u044c, \u0442\u0435\u043c \u0431\u043b\u0438\u0436\u0435 \u0446\u0432\u0435\u0442. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043a\u043e\u0441\u0442\u044b\u043b\u0438\u043c \u044d\u0442\u043e \u0434\u043b\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0425\u0430\u0431\u0440\u0430:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">var<\/span><span class=\"z-entity z-name z-function\"> depth<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-parameter\"> el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> d<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">d<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> el<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> el<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">parentElement<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">classList<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">contains<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">tm-comment-thread<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-variable z-other z-readwrite\"> d<\/span><span class=\"z-keyword z-operator\">++<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> d<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">var<\/span><span class=\"z-entity z-name z-function\"> color<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-parameter\"> el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation z-definition z-string\"> `<\/span><span class=\"z-string\">hsl(<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-constant z-numeric\">30<\/span><span class=\"z-keyword z-operator\"> *<\/span><span class=\"z-entity z-name z-function\"> depth<\/span><span class=\"z-string\">(<\/span><span class=\"z-variable z-other z-readwrite\">el<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> 70% 60%)<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__comment<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> `<\/span><span class=\"z-string\">border-left: solid 5px <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-entity z-name z-function\">color<\/span><span class=\"z-string\">(<\/span><span class=\"z-variable z-other z-readwrite\">el<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">;<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><\/span><\/code><\/pre>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/border-left-color-habr-before-after.png\" alt=\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b\" \/><\/p>\n<h2 id=\"panel-deistvii\"><a class=\"anchor\" href=\"#panel-deistvii\" title=\"link to section\">#<\/a>\u041f\u0430\u043d\u0435\u043b\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439<\/h2>\n<p>\u0412 Boost \u043f\u0430\u043d\u0435\u043b\u044c \u0441 \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0441\u043a\u0440\u044b\u0442\u0430 \u0438 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u0434\u043b\u0438\u043d\u043d\u043e\u043c\u0443 \u043d\u0430\u0436\u0430\u0442\u0438\u044e \u043d\u0430 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u043f\u043e\u0434 \u0441\u0430\u043c \u0442\u0435\u043a\u0441\u0442 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432. \u041d\u0430 \u0425\u0430\u0431\u0440\u0435, \u0432\u0438\u0434\u0438\u043c\u043e, \u043f\u043e \u0438\u043d\u0435\u0440\u0446\u0438\u0438 \u0441 \u0434\u0435\u0441\u043a\u0442\u043e\u043f\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u043a\u043d\u043e\u043f\u043a\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u043c \u0438\u0437 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/action-panel.png\" alt=\"\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u043f\u0430\u043d\u0435\u043b\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439\" \/><\/p>\n<p>\u0412\u0430\u0436\u043d\u0443\u044e \u043c\u0435\u0442\u0430\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0432\u0440\u043e\u0434\u0435 \u0434\u0430\u0442\u044b \u0438 \u0440\u0435\u0439\u0442\u0438\u043d\u0433\u0430, Boost \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u0441\u043f\u0440\u0430\u0432\u0430 \u043e\u0442 \u0438\u043c\u0435\u043d\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0442\u0430\u043c \u043c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e. \u0414\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u044f \u043d\u0435\u043c\u043d\u043e\u0436\u043a\u043e \u0441\u0447\u0438\u0442\u0435\u0440\u044e, \u0438 \u0441\u043a\u0440\u043e\u044e \u0444\u0443\u0442\u0435\u0440 \u0441\u043e\u0432\u0441\u0435\u043c. \u041f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0432 \u0441\u0432\u043e\u0435\u043c \u0432\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438 \u0447\u0438\u0441\u043b\u0430 \u0441\u043f\u0440\u0430\u0432\u0430 \u043e\u0442 \u043d\u0438\u043a\u0430.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-footer<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">display: none;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span><\/code><\/pre>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/comment-trees-ru\/action-bar-habr-before-after.png\" alt=\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b\" \/><\/p>\n<h2 id=\"rezul-taty\"><a class=\"anchor\" href=\"#rezul-taty\" title=\"link to section\">#<\/a>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b<\/h2>\n<p>\u0427\u0442\u043e \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c? \u041d\u0430 \u043e\u0434\u0438\u043d \u044d\u043a\u0440\u0430\u043d \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043b\u0435\u0437\u0430\u0435\u0442 \u0447\u0443\u0442\u044c \u043b\u0438 \u043d\u0435 \u0432 \u0434\u0432\u0430 \u0440\u0430\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0438\u0445 \u0433\u043b\u0443\u0431\u0438\u043d\u0430 \u0438 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043d\u0435 \u0445\u0443\u0436\u0435. \u042f \u043d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d, \u0432\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043b\u0438 \u0442\u0430\u043a\u043e\u0439 \u0434\u0438\u0437\u0430\u0439\u043d \u0432 \u0441\u0442\u0438\u043b\u044c \u0425\u0430\u0431\u0440\u0430, \u043d\u043e \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0420\u0435\u0434\u0434\u0438\u0442 \u0442\u0430\u043a \u0447\u0438\u0442\u0430\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e. \u0414\u0430 \u0438 \u0432 \u0446\u0435\u043b\u043e\u043c, \u043c\u043d\u0435 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u0430\u0447\u043d\u044b\u0439 \u0434\u0438\u0437\u0430\u0439\u043d \u0434\u043b\u044f \u0434\u0435\u0440\u0435\u0432\u0430 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432, \u0447\u0435\u043c \u0442\u043e\u0442, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u2014 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0434\u0430\u0436\u0435 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e! \u2014 \u043f\u0440\u0438\u0448\u043b\u0438 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0420\u0435\u0434\u0434\u0438\u0442\u0430.<\/p>\n<details>\n<summary>\u0412\u0435\u0441\u044c \u043c\u043e\u0439 \u043a\u043e\u0441\u0442\u044b\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438<\/summary>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u043b\u043e\u0441\u044c \u0432 Responsive Design Mode \u0438\u0437 Firefox \u0441 \u043f\u0440\u0435\u0441\u0435\u0442\u043e\u043c <code>Galaxy S10\/S10+ Android 11<\/code>.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"javascript\"><span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u041e\u0442\u0441\u0442\u0443\u043f\u044b<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__comment &gt; *<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">margin-left: 0;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">position: unset; margin-left: 5px;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__breadcrumbs<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">display: none;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__comment<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> `<\/span><span class=\"z-string\">border-left: solid 5px grey; margin-left: -10px;<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__children<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">padding-top: 0;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">margin-bottom: 0;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__comment<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">padding-top: 10px; border-top: solid 1px grey;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u0426\u0432\u0435\u0442 \u043a\u0430\u043a \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">var<\/span><span class=\"z-entity z-name z-function\"> depth<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-parameter\"> el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  let<\/span><span class=\"z-variable z-other z-readwrite\"> d<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  for<\/span><span class=\"z-source\"> (<\/span><span class=\"z-variable z-other z-readwrite\">d<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> el<\/span><span class=\"z-punctuation\">;<\/span><span class=\"z-variable z-other z-readwrite\"> el<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">parentElement<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-source\"> (<\/span><span class=\"z-source\">el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">classList<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">contains<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">tm-comment-thread<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-source\">)<\/span><span class=\"z-variable z-other z-readwrite\"> d<\/span><span class=\"z-keyword z-operator\">++<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-variable z-other z-readwrite\"> d<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">var<\/span><span class=\"z-entity z-name z-function\"> color<\/span><span class=\"z-keyword z-operator\"> =<\/span><span class=\"z-variable z-parameter\"> el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-punctuation z-definition z-string\"> `<\/span><span class=\"z-string\">hsl(<\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-constant z-numeric\">30<\/span><span class=\"z-keyword z-operator\"> *<\/span><span class=\"z-entity z-name z-function\"> depth<\/span><span class=\"z-string\">(<\/span><span class=\"z-variable z-other z-readwrite\">el<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\"> 70% 60%)<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-thread__comment<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-accessor\">  .<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> `<\/span><span class=\"z-string\">border-left: solid 5px <\/span><span class=\"z-punctuation\">${<\/span><span class=\"z-entity z-name z-function\">color<\/span><span class=\"z-string\">(<\/span><span class=\"z-variable z-other z-readwrite\">el<\/span><span class=\"z-string\">)<\/span><span class=\"z-punctuation\">}<\/span><span class=\"z-string\">;<\/span><span class=\"z-punctuation z-definition z-string\">`<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">\/\/<\/span><span class=\"z-comment\"> \u041f\u0430\u043d\u0435\u043b\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">$$<\/span><span class=\"z-source\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">.tm-comment-footer<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-entity z-name z-function\">forEach<\/span><span class=\"z-source\">(<\/span><span class=\"z-variable z-parameter\">el<\/span><span class=\"z-storage z-type\"> =&gt;<\/span><span class=\"z-source\"> el<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-source\">style<\/span><span class=\"z-punctuation z-accessor\">.<\/span><span class=\"z-variable z-other z-property z-js\">cssText<\/span><span class=\"z-keyword z-operator\"> +=<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">display: none;<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-source\">)<\/span><\/span>\n<span class=\"giallo-l\"><\/span><\/code><\/pre><\/details>\n"},{"title":"(\u041f\u0435\u0440\u0435\u0432\u043e\u0434) \u041a\u0430\u043a \u044f \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u043b \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c Netflix \u043d\u0430 Asahi Linux","published":"2023-03-10T00:00:00+00:00","updated":"2023-03-10T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/translations\/netflix-on-asahi-linux\/"}},"id":"https:\/\/iliazeus.lol\/translations\/netflix-on-asahi-linux\/","content":"<p>\u0413\u043e\u0434 \u043d\u0430\u0437\u0430\u0434 \u044f \u043a\u0443\u043f\u0438\u043b \u043c\u0430\u043a\u0431\u0443\u043a. \u041f\u043e\u043b\u0433\u043e\u0434\u0430 \u043d\u0430\u0437\u0430\u0434 macOS \u043d\u0430 \u043d\u0435\u043c \u0441\u043a\u0430\u0437\u0430\u043b\u0430 \"\u043e\u0439, \u0432\u0441\u0435\", \u0438 \u043e\u043d \u043e\u043a\u0438\u0440\u043f\u0438\u0447\u0438\u043b\u0441\u044f. \u042f \u0440\u0435\u0448\u0438\u043b \u043d\u0435 \u043f\u0435\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u0430 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c Asahi Linux, \u0438 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043d\u0435 \u043f\u043e\u0436\u0430\u043b\u0435\u043b \u043e\u0431 \u044d\u0442\u043e\u043c. \u0425\u043e\u0442\u044f \u043e\u0434\u043d\u0430 \u0432\u0435\u0449\u044c \u0432\u0441\u0435 \u0436\u0435 \u0440\u0430\u0437\u0434\u0440\u0430\u0436\u0430\u043b\u0430 \u2014 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 Netflix \u0438 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Spotify.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0447\u0435\u0441\u0442\u043d\u043e, Netflix \u043c\u043d\u0435 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c-\u0442\u043e \u0438 \u043d\u0443\u0436\u0435\u043d \u2014 \u0443 BitTorrent \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043b\u0443\u0447\u0448\u0435 UX. \u041d\u043e \u043a Spotify \u044f \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043b\u0441\u044f, \u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0438\u043c\u0435\u043d\u043d\u043e \u0443 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u0445\u043e\u0442\u044f \u043c\u043d\u043e\u0433\u0438\u043c \u044d\u0442\u043e \u0438 \u043f\u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u043d\u044b\u043c. \u041d\u043e \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 Spotify \u0434\u043b\u044f Linux \u043d\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 aarch64 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.<\/p>\n<p>\u0415\u0441\u0442\u044c, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, web-\u0432\u0435\u0440\u0441\u0438\u044f. \u0412\u0435\u0440\u043d\u0435\u0435, \u0431\u044b\u043b\u0430 \u0431\u044b, \u0435\u0441\u043b\u0438 \u0431\u044b \u043d\u0435 \u043e\u0448\u0438\u0431\u043a\u0430:<\/p>\n<blockquote>\n<p>Playback of protected content is not enabled.<\/p>\n<\/blockquote>\n<p>\u00ab\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u043e\u00bb, \u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u043d\u0442\u0435\u0435 \u2014 \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u043c\u043e\u0434\u0443\u043b\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/en.wikipedia.org\/wiki\/Widevine\">Widevine DRM<\/a>. \u041f\u043e \u044d\u0442\u043e\u0439 \u0436\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 Netflix.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043c\u044b \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u043d\u0430\u0448 \u0447\u0435\u043b\u043b\u0435\u043d\u0434\u0436 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439 \u043d\u0435 \u043d\u0430\u0440\u0443\u0448\u0438\u0442\u044c DMCA 2023! \u041d\u0430\u0448\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c Netflix \u043d\u0430 Asahi Linux, \u043d\u0435 \u043e\u0431\u0445\u043e\u0434\u044f \u0438 \u043d\u0435 \u043b\u043e\u043c\u0430\u044f DRM. (\u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0443\u043c\u0435\u0441\u0442\u0438\u0442\u0441\u044f \u0432 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/twitter.com\/David3141593\/status\/1080606827384131590\">280 \u0437\u043d\u0430\u043a\u043e\u0432<\/a>).<\/p>\n<h2 id=\"ustanovka-widevine\">\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 Widevine<\/h2>\n<p><img src=\"https:\/\/iliazeus.lol\/translations\/netflix-on-asahi-linux\/one-does-not-simply.png\" alt=\"one does not simply...\" \/><\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043d\u0435\u043b\u044c\u0437\u044f \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0437\u044f\u0442\u044c \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Widevine. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c Widevine \u2014 Chrome + Linux + x86_64. \u0412\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0441\u0440\u0430\u0437\u0443 \u0437\u0430\u0434\u0430\u0441\u0442 \u0432\u043e\u043f\u0440\u043e\u0441\u044b: \u043f\u043e\u0447\u0435\u043c\u0443 \u043e\u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0432 Firefox? \u041f\u043e\u0447\u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 Android, \u044d\u0442\u043e \u0436\u0435 \u0442\u043e\u0436\u0435 Linux \u043d\u0430 aarch64? \u041f\u043e\u0447\u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 Raspberry Pi?<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443.<\/p>\n<h3 id=\"pochemu-rabotaet-v-firefox-linux-x86-64\">\u041f\u043e\u0447\u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 Firefox + Linux + x86_64?<\/h3>\n<p>\u0412\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u043e\u0434\u0443\u043b\u044f\u043c DRM \u0447\u0435\u0440\u0435\u0437 API <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.w3.org\/TR\/encrypted-media\/\">Encrypted Media Extensions<\/a>. \u0412 \u0441\u0430\u043c\u043e\u043c Chrome DRM \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d, \u043e\u043d \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u044d\u0442\u043e \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a CDM, \u0438\u043b\u0438 Content Decryption Module. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 Chrome + Linux + x86_64, \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <code>libwedevinecdm.so<\/code> \u2014 \u043f\u0440\u043e\u043f\u0440\u0438\u0435\u0442\u0430\u0440\u043d\u044b\u0439 \u0431\u043b\u043e\u0431, \u0437\u0430\u0433\u043b\u044f\u0434\u044b\u0432\u0430\u0442\u044c \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043c \u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d\u043e.<\/p>\n<p>\u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u043c\u044b \u0437\u043d\u0430\u0435\u043c, \u043a\u0430\u043a \u0441 \u044d\u0442\u0438\u043c \u0431\u043b\u043e\u0431\u043e\u043c \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f: <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/chromium.googlesource.com\/chromium\/cdm\/\">\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0434\u043b\u044f C++<\/a> \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 Chromium. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 Firefox \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443 \u0441\u0435\u0431\u044f \u0440\u043e\u0432\u043d\u043e \u0442\u0443 \u0436\u0435 \u043f\u0440\u043e\u043f\u0440\u0438\u0435\u0442\u0430\u0440\u043d\u0443\u044e <code>libwidevinecdm.so<\/code>, \u0432\u0437\u044f\u0442\u0443\u044e \u0432 \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u043c \u0432\u0438\u0434\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438\u0437 Chrome. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0434\u043b\u044f Asahi Linux \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a \u0436\u0435 \u2014 \u0433\u043e\u0442\u043e\u0432\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f Chrome + Linux + aarch64 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.<\/p>\n<h3 id=\"pochemu-rabotaet-v-android-aarch64\">\u041f\u043e\u0447\u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 Android + aarch64?<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u0432\u043a\u0440\u0430\u0442\u0446\u0435, DRM \u043d\u0430 Android \u0432 \u0446\u0435\u043b\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e-\u0434\u0440\u0443\u0433\u043e\u043c\u0443. API \u0441\u0438\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f, \u0432\u0437\u044f\u0442\u044c \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c Widevine \u0434\u043b\u044f Android \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f, \u0430 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u0435\u0433\u043e \u043c\u0435\u0448\u0430\u0435\u0442 DMCA.<\/p>\n<h3 id=\"pochemu-rabotaet-na-raspberry-pi\">\u041f\u043e\u0447\u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 Raspberry Pi?<\/h3>\n<p>\u041a\u0430\u043a \u044f \u0443\u0436\u0435 \u0441\u043a\u0430\u0437\u0430\u043b, \u0441\u0432\u044f\u0437\u043a\u0430 Chrome + Linux + aarch64 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/p>\n<p>\u042f \u0441\u043e\u043b\u0433\u0430\u043b.<\/p>\n<p>\u0425\u0440\u043e\u043c\u0431\u0443\u043a\u0438. \u0412 \u0445\u0440\u043e\u043c\u0431\u0443\u043a\u0430\u0445 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Chrome, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u043f\u043b\u044e\u0441-\u043c\u0438\u043d\u0443\u0441 Linux, \u0438 \u043c\u043d\u043e\u0433\u0438\u0435 \u0438\u0437 \u043d\u0438\u0445 \u043d\u0430 aarch64. \u0420\u0430\u043d\u043e \u0438\u043b\u0438 \u043f\u043e\u0437\u0434\u043d\u043e \u043b\u044e\u0434\u0438 \u044d\u0442\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043b\u0438, \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/forums.raspberrypi.com\/viewtopic.php?t=347736\">\u0443\u0442\u0438\u043b\u0438\u0442\u0443<\/a>, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c <code>libwidevinecdm.so<\/code> \u0438\u0437 recovery-\u043e\u0431\u0440\u0430\u0437\u043e\u0432 \u0434\u043b\u044f \u0445\u0440\u043e\u043c\u0431\u0443\u043a\u043e\u0432. Raspberry Pi, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044f \u0437\u043d\u0430\u044e, \u0434\u043e\u0441\u0442\u0430\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e Widevine \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a, \u0434\u0430\u0436\u0435 \u0443\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u044f \u0432 <code>.deb<\/code>-\u043f\u0430\u043a\u0435\u0442.<\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0435\u0441\u0442\u044c \u0437\u0430\u0433\u0432\u043e\u0437\u0434\u043a\u0430. \u0425\u043e\u0442\u044f \u0432 \u0445\u0440\u043e\u043c\u0431\u0443\u043a\u0430\u0445 \u0435\u0441\u0442\u044c aarch64-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b \u0438 aarch64-\u044f\u0434\u0440\u0430 Linux, \u0432\u0435\u0441\u044c \u0438\u0445 userspace \u0432\u0441\u0435 \u0435\u0449\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u043b\u044f 32-\u0431\u0438\u0442\u043d\u043e\u0439 armv7l. \u0414\u043b\u044f Raspberry Pi \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u043d\u043e Apple Silicon \u043d\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043f\u0435\u0440\u0435\u0432\u0430\u0440\u0438\u0442\u044c 32-\u0431\u0438\u0442\u043d\u044b\u0439 \u043a\u043e\u0434. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430...<\/p>\n<p>...\u043d\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430! \u0422\u043e\u0447\u043d\u0435\u0435, <em>\u0443\u0436\u0435<\/em> \u043d\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430.<\/p>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043d\u0430\u0437\u0430\u0434, \u043a\u043e\u0433\u0434\u0430 \u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043d\u044f\u043b\u0441\u044f Widevine \u0434\u043b\u044f Asahi, \u0432\u0441\u0435 \u0431\u044b\u043b\u043e \u0442\u0430\u043a. \u041d\u043e \u043f\u0430\u0440\u0443 \u043d\u0435\u0434\u0435\u043b\u044c \u043d\u0430\u0437\u0430\u0434 \u0433\u0434\u0435-\u0442\u043e \u0432 Google \u0442\u0430\u043a\u0438 \u043d\u0430\u0441\u0442\u0443\u043f\u0438\u043b 21 \u0432\u0435\u043a, \u0438 \u043d\u0430 \u043d\u043e\u0432\u044b\u0445 \u0445\u0440\u043e\u043c\u0431\u0443\u043a\u0430\u0445 userspace \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f aarch64. \u0417\u043d\u0430\u0447\u0438\u0442, <code>libwidevinecdm.so<\/code> \u0434\u043b\u044f Linux + aarch64 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c \u0438\u0437 recovery-\u043e\u0431\u0440\u0430\u0437\u043e\u0432 ChromeOS, \u0447\u0442\u043e Pi Foundation <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/forums.raspberrypi.com\/viewtopic.php?t=347736\">\u0443\u0436\u0435 \u0443\u0441\u043f\u0435\u043b\u0430 \u0441\u0434\u0435\u043b\u0430\u0442\u044c<\/a>.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e \u0434\u043b\u044f...<\/p>\n<h2 id=\"widevine-dlia-arch-linux-na-arm\">Widevine \u0434\u043b\u044f Arch Linux \u043d\u0430 ARM<\/h2>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043d\u0435 \u0432\u0441\u0435 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e. ChromeOS \u2014 \u044d\u0442\u043e \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c Linux; \u043a\u0440\u043e\u043c\u0435 \u043f\u0440\u043e\u0447\u0435\u0433\u043e, \u0432 \u0435\u0433\u043e <code>glibc<\/code> \u0435\u0441\u0442\u044c \u043d\u0435 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0435 \u0441 Linux \u043f\u0430\u0442\u0447\u0438. \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0437\u044f\u0442\u044c \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c <code>libwidevinecdm.so<\/code>, \u043f\u043e\u043b\u0443\u0447\u0438\u043c segfault \u0433\u0434\u0435-\u0442\u043e \u0432 \u043d\u0435\u0434\u0440\u0430\u0445 <code>glibc<\/code>.<\/p>\n<p>\u042d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0440\u0435\u0448\u0430\u0435\u0442 \u043f\u0430\u043a\u0435\u0442 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/aur.archlinux.org\/packages\/glibc-widevine\">glibc-widevine<\/a>. \u041e\u043d \u043f\u0430\u0442\u0447\u0438\u0442 <code>glibc<\/code> \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438 \u0441 Widevine. \u041f\u043e\u0445\u043e\u0436\u0438\u0435 \u043f\u0430\u0442\u0447\u0438 \u0435\u0441\u0442\u044c \u0438 \u0432 <code>glibc<\/code> \u0434\u043b\u044f Raspbian, \u0440\u0430\u0437\u0432\u0435 \u0447\u0442\u043e \u0442\u0430\u043c \u043e\u043d\u0438 \u0438\u0434\u0443\u0442 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0440\u0430\u0442\u044c Chromium \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 Widevine \u2014 \u043d\u0430 Linux + aarch64 \u044d\u0442\u043e \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u0435 \u043e\u043d \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/archlinuxarm\/PKGBUILDs\/blob\/ad4a45f2\/extra\/chromium\/0001-widevine-support-for-arm.patch\">\u043f\u0430\u0442\u0447<\/a>.<\/p>\n<p>\u0418\u0442\u043e\u0433\u043e:<\/p>\n<ul>\n<li>Google \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442 \u043e\u0431\u0440\u0430\u0437 ChromeOS \u0434\u043b\u044f aarch64 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f userspace);<\/li>\n<li>Pi Foundation, \u0438\u043b\u0438 \u043a\u0442\u043e-\u0442\u043e \u0435\u0449\u0435, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u044e\u0442 \u043e\u0442\u0442\u0443\u0434\u0430 \u0431\u043b\u043e\u0431 \u0441 Widevine;<\/li>\n<li>\u0431\u043b\u043e\u0431 \u0443\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u044e\u0442 \u0432 <code>.deb<\/code>-\u043f\u0430\u043a\u0435\u0442 \u0434\u043b\u044f Raspbian;<\/li>\n<li>\u043d\u0430 <code>glibc<\/code> \u043d\u0430\u043a\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0430\u0442\u0447\u0438 \u0434\u043b\u044f \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438;<\/li>\n<li>\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u0442\u0447\u0435\u043d\u043d\u044b\u0439 Chromium \u0434\u043b\u044f ARM \u0441\u043e \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u043c Widevine;<\/li>\n<li>???<\/li>\n<\/ul>\n<h3 id=\"problema\">\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430<\/h3>\n<p>Asahi Linux \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/asahilinux.org\/2022\/03\/asahi-linux-alpha-release\/#known-broken-applications\">\u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043f\u0430\u043c\u044f\u0442\u0438 \u043f\u043e 16K<\/a>. \u0411\u043b\u043e\u0431 Widevine \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e 4K. \u041f\u0435\u0440\u0435\u0441\u043e\u0431\u0440\u0430\u0442\u044c \u044f\u0434\u0440\u043e \u043f\u043e\u0434 \u0434\u0440\u0443\u0433\u043e\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0441\u0442\u0440\u0430\u043d\u0438\u0446, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e, \u043d\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u044b \u043a\u043e\u0441\u0442\u044b\u043b\u0438 \u0438 \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0410 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u0438\u0437\u0430\u0441\u0441\u0435\u043c\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u043f\u0440\u0438\u0435\u0442\u0430\u0440\u043d\u044b\u0439 \u0431\u043b\u043e\u0431 \u043d\u0435\u043b\u044c\u0437\u044f.<\/p>\n<figure>\n<img src=\"dmca-violation-colorized.png\" \/>\n<figcaption>\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 \u0437\u0430\u0433\u043b\u044f\u043d\u0443\u043b \u0432\u043d\u0443\u0442\u0440\u044c \u0431\u043b\u043e\u0431\u0430 Widevine. \u0424\u043e\u0442\u043e \u0432 \u0446\u0432\u0435\u0442\u0435.<\/figcaption>\n<\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c, \u0432 \u0447\u0435\u043c \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0442\u043e, \u043a\u0430\u043a <code>libwidevinecdm.so<\/code> \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0430\u043c\u044f\u0442\u044c. \u041a\u0430\u043a \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 <code>.so<\/code>-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0432\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e ELF \u2014 Executable and Linkable Format \u2014 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u043e\u043c \u2014 \u044f\u0434\u0440\u043e\u043c \u0438\u043b\u0438 <code>ld.so<\/code> \u2014 \u0438 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u0435\u043c\u0443, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043a\u043e\u0434 \u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0438\u0445 \u043a \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044e.<\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u0444\u0430\u0439\u043b\u043e\u0432 ELF \u0435\u0441\u0442\u044c Program Header Table \u2014 \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u0414\u043b\u044f \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u0441 \u0442\u0438\u043f\u043e\u043c <code>LOAD<\/code> \u0442\u0430\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u043e, \u043a\u0430\u043a \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0441\u0435\u0433\u043c\u0435\u043d\u0442 \u0432 \u043f\u0430\u043c\u044f\u0442\u044c, \u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u043b\u0438 \u044d\u0442\u0443 \u043f\u0430\u043c\u044f\u0442\u044c \u0447\u0438\u0442\u0430\u0442\u044c\/\u043f\u0438\u0441\u0430\u0442\u044c\/\u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0442\u044c.<\/p>\n<p>\u0421 \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435\u043c \u044d\u0442\u0438\u0445 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430. \u041e\u043d\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u0430\u043c\u0438 <code>mmap()<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/man7.org\/linux\/man-pages\/man2\/mmap.2.html\">\u0442\u0440\u0435\u0431\u0443\u0435\u0442<\/a>:<\/p>\n<ul>\n<li>\u0447\u0442\u043e\u0431\u044b \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430 \u043e\u0442 \u043d\u0430\u0447\u0430\u043b\u0430 \u0444\u0430\u0439\u043b\u0430 \u0431\u044b\u043b\u043e \u043a\u0440\u0430\u0442\u043d\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u0430\u043c\u044f\u0442\u0438;<\/li>\n<li>\u0447\u0442\u043e\u0431\u044b \u0430\u0434\u0440\u0435\u0441 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438, \u043a\u0443\u0434\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0441\u0435\u0433\u043c\u0435\u043d\u0442, \u0431\u044b\u043b \u0432\u044b\u0440\u043e\u0432\u043d\u0435\u043d \u043f\u043e \u0433\u0440\u0430\u043d\u0438\u0446\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/li>\n<\/ul>\n<p>\u0417\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/bminor\/glibc\/blob\/10f980d3\/elf\/dl-load.c#L1134-L1143\">\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442<\/a> \u044d\u0442\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"c\"><span class=\"giallo-l\"><span class=\"z-source\">case PT_LOAD:<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/*<\/span><span class=\"z-comment\"> A load command tells us to map in part of the file.<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-comment\">       We record the load commands and process them all later.  <\/span><span class=\"z-punctuation z-definition z-comment\">*\/<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-entity z-name z-function\">__glibc_unlikely<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">ph<\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\">p_vaddr <\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-source\"> ph<\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\">p_offset<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">         &amp;<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-entity z-name z-function\">GLRO<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">dl_pagesize<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\"> -<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-keyword z-operator\"> !=<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">        errstring<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword z-operator\">    =<\/span><span class=\"z-entity z-name z-function\"> N_<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">ELF load command address\/offset not page-aligned<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">        goto<\/span><span class=\"z-source\"> lose<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">      }<\/span><\/span><\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0441\u0442\u0430\u0442\u044c <code>goto loser<\/code>\u043e\u043c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e <code>(vaddr - offset) % pagesize == 0<\/code>, \u0433\u0434\u0435 <code>vaddr<\/code> \u2014 Virtual (memory) Address \u2014 \u0430\u0434\u0440\u0435\u0441 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438, \u043a\u0443\u0434\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0441\u0435\u0433\u043c\u0435\u043d\u0442, \u0430 <code>offset<\/code> \u2014 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0444\u0430\u0439\u043b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<p>\u0412\u043e\u0442 Program Header Table \u0434\u043b\u044f \u043c\u043e\u0435\u0439 \u043a\u043e\u043f\u0438\u0438 <code>libwidevinecdm.so<\/code>:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>Type             Offset     VAddr      FileSize   MemSize    Align      Prot<\/span><\/span>\n<span class=\"giallo-l\"><span>PT_PHDR          0x00000040 0x00000040 0x00000230 0x00000230 0x00000008 r--<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span>PT_LOAD          0x00000000 0x00000000 0x00904290 0x00904290 0x00001000 r-x<\/span><\/span>\n<span class=\"giallo-l\"><span>PT_LOAD          0x00904290 0x00905290 0x00007500 0x00007500 0x00001000 rw-<\/span><\/span>\n<span class=\"giallo-l\"><span>PT_LOAD          0x0090b790 0x0090d790 0x00000df0 0x00c36698 0x00001000 rw-<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span>PT_TLS           0x00904290 0x00905290 0x00000018 0x00000018 0x00000008 r--<\/span><\/span>\n<span class=\"giallo-l\"><span>PT_DYNAMIC       0x00909618 0x0090a618 0x00000220 0x00000220 0x00000008 rw-<\/span><\/span>\n<span class=\"giallo-l\"><span>PT_GNU_RELRO     0x00904290 0x00905290 0x00007500 0x00007d70 0x00000001 r--<\/span><\/span>\n<span class=\"giallo-l\"><span>PT_GNU_EH_FRAME  0x00524a24 0x00524a24 0x000010fc 0x000010fc 0x00000004 r--<\/span><\/span>\n<span class=\"giallo-l\"><span>PT_GNU_STACK     0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 rw-<\/span><\/span>\n<span class=\"giallo-l\"><span>PT_NOTE          0x00000270 0x00000270 0x00000024 0x00000024 0x00000004 r--<\/span><\/span><\/code><\/pre>\n<p>\u042f \u0432\u044b\u0434\u0435\u043b\u0438\u043b \u043f\u0443\u0441\u0442\u044b\u043c\u0438 \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438 \u0442\u0440\u0438 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430 <code>PT_LOAD<\/code>.<\/p>\n<p>\u0415\u0441\u043b\u0438 pagesize == 0x1000 (4 \u041a\u0411), \u0442\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432. \u041d\u043e \u0441\u0442\u043e\u0438\u0442 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c pagesize \u0434\u043e 0x4000 (16 \u041a\u0411), \u043a\u0430\u043a \u0432 Asahi Linux, \u043a\u0430\u043a \u0432\u0442\u043e\u0440\u043e\u0439 \u0438 \u0442\u0440\u0435\u0442\u0438\u0439 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b <code>PT_LOAD<\/code> \u0441\u0442\u0430\u043d\u0443\u0442 \u0435\u0433\u043e \u043d\u0430\u0440\u0443\u0448\u0430\u0442\u044c. \u0414\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u0432\u0430\u0436\u043d\u043e \u2014 \u043e\u043d\u0438 \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0447\u0435\u0440\u0435\u0437 <code>mmap()<\/code>.<\/p>\n<h3 id=\"reshenie\">\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/h3>\n<p>\u041c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0430 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u043d\u0435\u043b\u044c\u0437\u044f \u2014 \u044d\u0442\u043e \u0441\u043b\u043e\u043c\u0430\u0435\u0442 \u0432 \u043a\u043e\u0434\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0438\u0437 \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430 \u0432 \u0434\u0440\u0443\u0433\u043e\u0439. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 DRM \u2014 \u043e\u043d\u0430 \u0437\u043b\u0438\u0442\u0441\u044f \u043d\u0430 \u043b\u044e\u0431\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u0435\u0431\u044f \u0432 \u043f\u0430\u043c\u044f\u0442\u0438. \u0410 \u043d\u0430 \u043a\u043e\u043f\u0430\u043d\u0438\u0435 \u0432 \u043a\u043e\u0434\u0435 \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0437\u043b\u0438\u0442\u0441\u044f DMCA.<\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0449\u0435 \u0440\u0430\u0437 \u043d\u0430 \u043d\u0430\u0448\u0435 \u0437\u043b\u043e\u043f\u043e\u043b\u0443\u0447\u043d\u043e\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 <code>(vaddr - offset) % pagesize == 0<\/code>. \u041c\u0435\u043d\u044f\u0442\u044c <code>vaddr<\/code> \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u043f\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c \u0432\u044b\u0448\u0435. \u041d\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c <code>offset<\/code>, \u0435\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043c \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b \u0432 \u0441\u0430\u043c\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0435\u0440\u0432\u043e\u0433\u043e <code>PT_LOAD<\/code> \u043d\u0438\u0447\u0435\u0433\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e, \u043d\u043e \u0432\u043e\u0442 \u0434\u043b\u044f \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c <code>vaddr - offset == 0x00905290 - 0x00904290 == 0x1000<\/code>. \u0418\u0441\u043f\u0440\u0430\u0432\u0438\u043c \u044d\u0442\u043e, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 <code>0x1000<\/code> \u0431\u0430\u0439\u0442 \u043f\u0430\u0434\u0434\u0438\u043d\u0433\u0430 \u043c\u0435\u0436\u0434\u0443 \u043f\u0435\u0440\u0432\u044b\u043c \u0438 \u0432\u0442\u043e\u0440\u044b\u043c \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435, \u043d\u0435 \u0437\u0430\u0431\u044b\u0432 \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c <code>offset<\/code>. \u0422\u0435\u043f\u0435\u0440\u044c <code>vaddr - offset == 0x00904290 - 0x00904290 == 0<\/code>. \u0421 \u0442\u0440\u0435\u0442\u044c\u0438\u043c \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u043c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e.<\/p>\n<p>\u041f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043f\u0430\u0434\u0434\u0438\u043d\u0433\u0430 \u0432 ELF \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u043e\u043b\u044f. \u041d\u043e \u043c\u044b \u043c\u0435\u043d\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c ELF-\u0444\u0430\u0439\u043b \u2014 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0439 \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b\u043c \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u0443, \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u043c\u0443 \u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438 \u043f\u0430\u043c\u044f\u0442\u0438 \u043f\u043e 4K. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u0440\u0438 \u0441\u0430\u043c\u043e\u043f\u0440\u043e\u0432\u0440\u043a\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u0430\u043f\u043e\u0434\u043e\u0437\u0440\u0438\u0442 \u0438 \u043d\u0435 \u0440\u0430\u0437\u043e\u0437\u043b\u0438\u0442\u0441\u044f.<\/p>\n<h3 id=\"granuliarnost-razreshenii\">\u0413\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0439<\/h3>\n<p>\u0412 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u0441 4K-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438 \u043a\u0430\u0436\u0434\u044b\u0435 4\u041a\u0411 \u043f\u0430\u043c\u044f\u0442\u0438 \u043c\u043e\u0433\u0443\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u0432\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435\/\u0437\u0430\u043f\u0438\u0441\u044c\/\u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u043a\u0430 \u0431\u044b\u043b\u0430 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u044d\u0442\u043e\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438. \u041d\u043e \u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u0441 16K-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438 \u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u0442\u0430\u043a\u0438\u0445 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0439 16\u041a\u0411. \u042d\u0442\u043e \u043f\u043e\u0440\u043e\u0436\u0434\u0430\u0435\u0442 \u0434\u0432\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u043a\u0446\u0438\u0438 <code>.text<\/code> \u2014 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u2014 \u0438 \u0441\u0435\u043a\u0446\u0438\u0438 <code>.data<\/code> \u2014 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u2014 \u0442\u0435\u043f\u0435\u0440\u044c \u0438\u043c\u0435\u044e\u0442 \u043e\u0431\u0449\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u041f\u0435\u0440\u0432\u044b\u043c \u043d\u0443\u0436\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435, \u0432\u0442\u043e\u0440\u044b\u043c \u2014 \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u043f\u0438\u0441\u044c. \u0414\u0430\u0442\u044c \u0438 \u0442\u043e, \u0438 \u0434\u0440\u0443\u0433\u043e\u0435 \u043c\u043e\u0436\u043d\u043e, \u043d\u043e \u044d\u0442\u043e \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u044b\u0440\u0430 \u0432 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438. \u041f\u043e\u043a\u0430 \u0447\u0442\u043e \u044f \u043d\u0435 \u043d\u0430\u0448\u0435\u043b \u0441\u043f\u043e\u0441\u043e\u0431 \u044d\u0442\u043e\u0433\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c.<\/p>\n<p>\u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043f\u043e \u0442\u043e\u0439 \u0436\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c RELRO \u2014 Relocation Read-Only \u2014 \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u043c\u0435\u0440\u0443 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043c\u0435\u0447\u0430\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u043a\u0446\u0438\u0438 \u043a\u0430\u043a read-only \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438.<\/p>\n<p>\u0421\u0430\u043c\u043e \u043f\u043e \u0441\u0435\u0431\u0435 \u044d\u0442\u043e \u2014 \u043d\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438, \u043d\u043e \u044d\u0442\u043e \u043e\u0441\u043b\u0430\u0431\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0449\u0438\u0442\u044b \u043f\u0440\u043e\u0442\u0438\u0432 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445. \u0417\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a, \u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0442\u0430\u043a\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434, \u0430 \u0437\u0430\u0442\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0435\u0433\u043e. \u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435, \u0435\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0439\u0442\u0438 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u0432\u0430\u0441 \u043f\u0443\u0433\u0430\u0435\u0442, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f Netflix \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440.<\/p>\n<h3 id=\"patching-elf\">\u041f\u0430\u0442\u0447\u0438\u043d\u0433 ELF<\/h3>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/lief-project\/LIEF\">LIEF<\/a>, \u043d\u043e \u0442\u043e \u043b\u0438 \u0438\u0437-\u0437\u0430 \u0431\u0430\u0433\u043e\u0432, \u0442\u043e \u043b\u0438 \u0438\u0437-\u0437\u0430 \u043a\u0440\u0438\u0432\u043e\u0441\u0442\u0438 \u0440\u0443\u043a \u0443 \u043c\u0435\u043d\u044f \u043d\u0435 \u0432\u044b\u0448\u043b\u043e. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u044f \u0432 \u043a\u043e\u0444\u0435\u0438\u043d\u043e\u0432\u043e\u043c \u0442\u0440\u0430\u043d\u0441\u0435 \u0440\u0430\u0441\u0447\u0435\u0445\u043b\u0438\u043b <code>hexedit<\/code> \u0438 \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043b \u0432\u0441\u0435 \u0440\u0443\u043a\u0430\u043c\u0438. \u041a \u043c\u043e\u0435\u043c\u0443 \u0443\u0434\u0438\u0432\u043b\u0435\u043d\u0438\u044e, \u044d\u0442\u043e \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e!<\/p>\n<p>\u041d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d, \u0447\u0442\u043e \u044f \u043c\u043e\u0433\u0443 \u043b\u0435\u0433\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0442\u044c \u043f\u0430\u0442\u0447\u0435\u043d\u044b\u0439 ELF, \u043d\u043e \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/gist.github.com\/DavidBuchanan314\/c6b97add51b97e4c3ee95dc890f9e3c8\">\u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 \u043f\u0438\u0442\u043e\u043d\u0435<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u043f\u0430\u0442\u0447\u0438\u0442\u044c \u0435\u0433\u043e \u0441\u0430\u043c\u0438. \u0414\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442, \u0438 \u0432\u043e\u0442 \u0443 \u0432\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c <code>libwedevinecdm.so<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c Firefox \u043f\u043e\u0434 Asahi Linux!<\/p>\n<h2 id=\"final-nye-shtrikhi\">\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0448\u0442\u0440\u0438\u0445\u0438<\/h2>\n<p>\u0418\u0437-\u0437\u0430 \u0441\u0442\u0440\u0430\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 <code>glibc<\/code> \u043d\u0430 ChromeOS, \u043e \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044f \u0433\u043e\u0432\u043e\u0440\u0438\u043b \u0440\u0430\u043d\u0435\u0435, \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u0447\u043a\u0443 \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 <code>__aarch64_ldadd4_acq_rel<\/code> \u0438 <code>__aarch64_swp4_acq_rel<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u043b \u0447\u0435\u0440\u0435\u0437 <code>LD_PRELOAD<\/code>. \u042d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043a\u0440\u0430\u0441\u0438\u0432\u043e, \u0438 \u044f \u0441\u0442\u0430\u043b \u0434\u0443\u043c\u0430\u0442\u044c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u044d\u0442\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u0441\u0430\u043c <code>libwidevinecdm.so<\/code>.<\/p>\n<p>\u0415\u0449\u0435 \u043f\u043e\u043c\u043d\u0438\u0442\u0435, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0443\u0434\u0430 0x1000 \u0431\u0430\u0439\u0442\u043e\u0432 \u0434\u043b\u044f \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u044f? \u041e\u043d\u0438 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u0443\u044e \u043f\u0430\u043c\u044f\u0442\u044c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0437\u0430\u0441\u0443\u043d\u0443\u043b \u044d\u0442\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0442\u0443\u0434\u0430! \u042f \u0431\u043e\u044f\u043b\u0441\u044f, \u0447\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f, \u043d\u043e, \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u043e\u043d\u0430 \u0438\u0445 \u043d\u0435 \u0437\u0430\u043c\u0435\u0442\u0438\u043b\u0430 \u043f\u0440\u0438 \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u0445. \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0438\u0445 \u0430\u0434\u0440\u0435\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 Global Offset Table \u2014 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u043e\u043c \u0438\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u0430\u043c\u043e\u043c ELF. \u042f \u0437\u0430\u043c\u0435\u043d\u0438\u043b \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438 \u043d\u0430 \u043c\u0435\u0441\u0442\u043e, \u043a\u0443\u0434\u0430 \u044f \u0434\u043e\u043f\u0438\u0441\u0430\u043b \u043d\u043e\u0432\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438.<\/p>\n<p>\u0412\u0441\u0435 \u044d\u0442\u043e \u044f \u0432\u043a\u043b\u044e\u0447\u0438\u043b \u0432 \u0441\u0432\u043e\u0439 Python-\u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439, \u0441 \u043e\u0434\u043e\u0431\u0440\u0435\u043d\u0438\u044f \u043c\u0435\u0439\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0432 \u043f\u0430\u043a\u0435\u0442 <code>widevine-aarch64<\/code>. \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c <code>widevine-aarch64<\/code> \u0438\u0437 AUR, \u0438 \u0441 Widevine \u043d\u0430 Asahi Linux \u0431\u0443\u0434\u0435\u0442 \u0433\u043e\u0442\u043e\u0432 \u043a \u0440\u0430\u0431\u043e\u0442\u0435!<\/p>\n<h3 id=\"osobennosti-netflix\">\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 Netflix<\/h3>\n<p>Spotify \u0443 \u043c\u0435\u043d\u044f \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b, \u043d\u043e Netflix \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0441\u044f \u0447\u0442\u043e-\u043b\u0438\u0431\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c. \u0414\u0435\u043b\u043e \u0431\u044b\u043b\u043e \u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 User-Agent. \u0412 \u043a\u043e\u043d\u0446\u0435-\u043a\u043e\u043d\u0446\u043e\u0432, \u044f \u043f\u043e\u043c\u0435\u043d\u044f\u043b \u0435\u0433\u043e \u043d\u0430 \u0432\u0437\u044f\u0442\u044b\u0439 \u0438\u0437 ChromeOS:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>Mozilla\/5.0 (X11; CrOS aarch64 15236.80.0) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/109.0.5414.125 Safari\/537.36<\/span><\/span><\/code><\/pre>\n<p>\u0412\u0435\u0440\u0441\u0438\u044f Widevine, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438, \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f L3 \u2014 \u043d\u0430\u0438\u043c\u0435\u043d\u0435\u0435 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c. \u0411\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u0438\u0435 \u0443\u0440\u043e\u0432\u043d\u0438 \u0437\u0430\u0449\u0438\u0442\u044b \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438. \u041d\u0430 Apple Silicon \u0435\u0441\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0435 \u0447\u0438\u043f\u044b, \u043d\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043d\u0435 \u0440\u043e\u0434\u043d\u0430\u044f, \u0438 \u0438\u0445 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0442\u0430\u043c \u043d\u0435\u0442.<\/p>\n<p>\u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0435 \u0434\u0430\u044e\u0442 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c 4K-\u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u043d\u0430 \u0442\u0430\u043a\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u0437\u0430\u0449\u0438\u0442\u044b \u2014 \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 1080p. \u041d\u043e Netflix \u0438 \u0442\u0443\u0442 \u043e\u0442\u043b\u0438\u0447\u0438\u043b\u0441\u044f: \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043e\u043d \u043e\u0442\u0434\u0430\u0435\u0442 \u0442\u0430\u043a\u0438\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c 720p, \u0430 1080p \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442, \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u0435\u0433\u043e \u043e\u0441\u043e\u0431\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/chrome.google.com\/webstore\/detail\/netflix-1080p\/cankofcoohmbhfpcemhmaaeennfbnmgp?hl=en\">\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f<\/a>. \u041d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d, \u0437\u0430\u0447\u0435\u043c \u043e\u043d\u0438 \u0442\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u043b\u0438; \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0443 \u043a\u043e\u0433\u043e-\u0442\u043e \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0431\u044b\u043b\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0438\u0437-\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 L3-\u0432\u0435\u0440\u0441\u0438\u0435\u0439 \"\u0436\u0435\u043b\u0435\u0437\u043d\u043e\u0433\u043e\" \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0438\u0434\u0435\u043e?<\/p>\n<h2 id=\"zakliuchenie\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041c\u0435\u043d\u044f \u0437\u0430\u0431\u0430\u0432\u043b\u044f\u0435\u0442, \u0447\u0442\u043e \u0432\u0441\u0435 \u044d\u0442\u043e \u044f \u0434\u0435\u043b\u0430\u043b \u043d\u0435 \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043e\u0439\u0442\u0438 DRM, \u0430 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u043e \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e. \u042d\u0442\u043e \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e! \u0418\u0437 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u0441\u043c\u043e\u0433 \u043b\u0435\u0433\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b, \u0432 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u043c \u043c\u0438\u0440\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u0434\u0435\u0442\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438!<\/p>\n<p>\u0414\u043e\u0440\u043e\u0433\u043e\u0439 \u0413\u0443\u0433\u043b, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0434\u043e\u0431\u0430\u0432\u044c \u0432 \u043c\u0430\u0442\u0440\u0438\u0446\u0443 \u0441\u0431\u043e\u0440\u043a\u0438 \u0445\u043e\u0442\u044f \u0431\u044b Ubuntu \u043d\u0430 aarch64. \u042f \u0437\u043d\u0430\u044e, \u0442\u0435\u0431\u0435 \u043d\u0435 \u0441\u043b\u043e\u0436\u043d\u043e.<\/p>\n"},{"title":"\u041a\u0430\u043a (\u0438 \u0437\u0430\u0447\u0435\u043c) \u044f \u043f\u0438\u0441\u0430\u043b README \u0432 Jupyter-\u043d\u043e\u0443\u0442\u0431\u0443\u043a\u0435 \u0434\u043b\u044f Node.js-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f","published":"2022-12-23T00:00:00+00:00","updated":"2022-12-23T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/node-jupyter-readme-ru\/"}},"id":"https:\/\/iliazeus.lol\/articles\/node-jupyter-readme-ru\/","summary":"<p>\u041d\u0430 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u043c\u0435\u0441\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043b \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u0443\u044e Node.js-\u0443\u0442\u0438\u043b\u0438\u0442\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u0432 NPM. \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/commander\"><code>commander<\/code><\/a>, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b\u0430 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0434\u043a\u043e\u043c\u0430\u043d\u0434, \u0438 \u0432\u0441\u0435 \u043e\u043d\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0432 README-\u0444\u0430\u0439\u043b\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438. \u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0442 \u0441\u043f\u0443\u0441\u0442\u044f \u044f \u043d\u0430\u0448\u0435\u043b \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0435 \u0434\u043b\u044f \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b Node.js \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438.<\/p>\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/node-jupyter-readme-ru\/cover.png\" alt=\"README.ipynb\" \/><\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435: \u043c\u043d\u043e\u0433\u043e \u043c\u043e\u0435\u0439 \u043b\u044e\u0431\u0432\u0438 \u043a <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/jupyter.org\/\">Jupyter<\/a>-\u043f\u043e\u0434\u043e\u0431\u043d\u044b\u043c \u043d\u043e\u0443\u0442\u0431\u0443\u043a\u0430\u043c, \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u0440\u043e \u0442\u043e, \u043a\u0430\u043a \u0437\u0430\u0442\u0430\u0449\u0438\u0442\u044c Python-\u043f\u0430\u043a\u0435\u0442 \u0432 NPM \u0438 \u0447\u0443\u0442\u044c-\u0447\u0443\u0442\u044c \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0442\u0440\u0435\u043a\u0435\u0440\u043d\u043e\u0439 \u043c\u0443\u0437\u044b\u043a\u0438.<\/p>"},{"title":"(\u041f\u0435\u0440\u0435\u0432\u043e\u0434) http:\/\/http:\/\/http:\/\/@http:\/\/http:\/\/?http:\/\/#http:\/\/","published":"2022-09-09T00:00:00+00:00","updated":"2022-09-09T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/translations\/http-http-http\/"}},"id":"https:\/\/iliazeus.lol\/translations\/http-http-http\/","summary":"<p>\u041f\u0430\u0440\u0443 \u0434\u043d\u0435\u0439 \u043d\u0430\u0437\u0430\u0434 \u044f \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b \u044d\u0442\u043e\u0442 \u0442\u0432\u0438\u0442:<\/p>\n<figure class=\"border\">\n<img src=\"tweet.png\" alt=\"&quot;http:\/\/http:\/\/http:\/\/@http:\/\/http:\/\/?http:\/\/#http:\/\/&quot; is a legitimate URL\" \/>\n<\/figure>\n<p>\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u0442\u043e, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u043d\u043e\u0433\u043e \u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432, \u044f \u0440\u0435\u0448\u0438\u043b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u044d\u0442\u043e \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435. \u041f\u0440\u0430\u0432\u0434\u0430 \u043b\u0438 \u044d\u0442\u043e \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 URL? \u0412\u043e \u0447\u0442\u043e \u043e\u043d \u043f\u0430\u0440\u0441\u0438\u0442\u0441\u044f? <em>\u0427\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0442\u0430\u043a\u043e\u0435 URL?<\/em><\/p>"},{"title":"\u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f* \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u043a\u0430 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0432 JavaScript","published":"2022-04-01T00:00:00+00:00","updated":"2022-04-01T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/articles\/js-magic-overload-ru\/"}},"id":"https:\/\/iliazeus.lol\/articles\/js-magic-overload-ru\/","summary":"<figure class=\"border\">\n<p><img src=\"https:\/\/iliazeus.lol\/articles\/js-magic-overload-ru\/cover.png\" alt=\"\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u043a\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432\" \/><\/p>\n<\/figure>\n<p>\u041e\u0434\u043d\u0430 \u0438\u0437 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u0444\u0438\u0447 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/tc39\/proposal-operator-overloading\">\u0432 JavaScript<\/a> \u0438 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues?q=is%3Aissue+operator+overloading\">\u0432 TypeScript<\/a> \u2014 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u043a\u0430 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432. \u0411\u0435\u0437 \u0438\u043d\u0444\u0438\u043a\u0441\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u0433\u0440\u043e\u043c\u043e\u0437\u0434\u043a\u0438\u043c\u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0441 \u0432\u0435\u043a\u0442\u043e\u0440\u0430\u043c\u0438 \u0438\u043b\u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430\u043c\u0438. \u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <strike>\u0441\u0438\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0434\u0443\u043d\u0441\u0442\u0432\u043e<\/strike> \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u0435\u0439\u0447\u0430\u0441 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0432 JavaScript, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>"},{"title":"(\u041f\u0435\u0440\u0435\u0432\u043e\u0434) \u041a\u0430\u043a \u044f \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u043b GTA Online \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u043d\u0430 70% \u0431\u044b\u0441\u0442\u0440\u0435\u0435","published":"2021-03-01T00:00:00+00:00","updated":"2021-03-01T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/translations\/gta-online-loading-times\/"}},"id":"https:\/\/iliazeus.lol\/translations\/gta-online-loading-times\/","content":"<p>GTA Online \u043f\u0435\u0447\u0430\u043b\u044c\u043d\u043e \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u0441\u0432\u043e\u0438\u043c\u0438 \u0447\u0443\u0434\u043e\u0432\u0438\u0449\u043d\u043e \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430\u043c\u0438. \u0420\u0435\u0448\u0438\u0432 \u0441\u043d\u043e\u0432\u0430 \u043f\u043e\u0438\u0433\u0440\u0430\u0442\u044c \u0432 \u043d\u0435\u0435 \u0440\u0430\u0434\u0438 \u043f\u0430\u0440\u044b \u043d\u043e\u0432\u044b\u0445 \u043c\u0438\u0441\u0441\u0438\u0439, \u044f \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b <em>(\u0432\u043e\u0442 \u0441\u044e\u0440\u043f\u0440\u0438\u0437!)<\/em>, \u0447\u0442\u043e \u0432\u0441\u0435 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0436\u0435 \u043f\u043b\u043e\u0445\u043e, \u043a\u0430\u043a \u0438 \u0441\u0435\u043c\u044c \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434, \u0432 \u0434\u0435\u043d\u044c \u0435\u0435 \u0440\u0435\u043b\u0438\u0437\u0430.<\/p>\n<p>\u041d\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u044d\u0442\u0438\u043c \u0440\u0430\u0437 \u0438 \u043d\u0430\u0432\u0441\u0435\u0433\u0434\u0430.<\/p>\n<h3 id=\"razvedka\">\u0420\u0430\u0437\u0432\u0435\u0434\u043a\u0430<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0441\u044f \u043d\u0430 \u043f\u043e\u0438\u0441\u043a\u0438 \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u0411\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u043b\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u043e \u0442\u043e\u043c, <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/metro.co.uk\/2017\/11\/01\/why-does-gta-v-take-so-long-to-load-7041927\/\">\u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0436\u043d\u0430 \u0438\u0433\u0440\u0430<\/a>, <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/steamcommunity.com\/app\/271590\/discussions\/0\/217690940938819317\/\">\u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u043e\u0445\u0430 \u0441\u0435\u0442\u0435\u0432\u0430\u044f p2p-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/a> (\u0447\u0442\u043e, \u0432 \u043e\u0431\u0449\u0435\u043c-\u0442\u043e, \u043f\u0440\u0430\u0432\u0434\u0430), <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/gtaforums.com\/topic\/908000-fastest-way-to-load-into-gtao-single-player-first-or-straight-in\/\">\u0445\u0430\u043a\u0438 \u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439 \u0438\u0437 \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430<\/a>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0430\u0440\u043e\u0447\u043a\u0430 \u043c\u043e\u0434\u043e\u0432, \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0445 \u0432\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438. \u041f\u043e \u043c\u043e\u0438\u043c \u0441\u043a\u0440\u043e\u043c\u043d\u044b\u043c \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430\u043c, \u0432\u0441\u0435 \u044d\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0430\u0436 \u0446\u0435\u043b\u044b\u0445 10-30 \u0441\u0435\u043a\u0443\u043d\u0434!<\/p>\n<h3 id=\"benchmarki\">\u0411\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0438<\/h3>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>Story mode load time:  ~1m 10s<\/span><\/span>\n<span class=\"giallo-l\"><span>Online mode load time: ~6m flat<\/span><\/span>\n<span class=\"giallo-l\"><span>Startup menu disabled, time from R* logo until in-game (social club login time isn&#39;t counted).<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span>Old but decent CPU:   AMD FX-8350<\/span><\/span>\n<span class=\"giallo-l\"><span>Cheap-o SSD:          KINGSTON SA400S37120G<\/span><\/span>\n<span class=\"giallo-l\"><span>We have to have RAM:  2x Kingston 8192 MB (DDR3-1337) 99U5471<\/span><\/span>\n<span class=\"giallo-l\"><span>Good-ish GPU:         NVIDIA GeForce GTX 1070<\/span><\/span><\/code><\/pre>\n<p>\u042f \u043f\u043e\u043d\u0438\u043c\u0430\u044e, \u0447\u0442\u043e \u043c\u043e\u0435 \u0436\u0435\u043b\u0435\u0437\u043e \u043d\u0435 \u0441\u0430\u043c\u043e\u0435 \u043d\u043e\u0432\u043e\u0435, \u043d\u043e \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0433\u043e \u0432 \u0441\u0435\u0442\u0435\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u0432 \u0448\u0435\u0441\u0442\u044c \u0440\u0430\u0437 \u0434\u043e\u043b\u044c\u0448\u0435 \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u043e\u0433\u043e? \u041a \u0441\u043b\u043e\u0432\u0443, \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430 \u043c\u043d\u0435 \u043d\u0435 \u043f\u043e\u043c\u043e\u0433\u043b\u043e (<a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.reddit.com\/r\/gtaonline\/comments\/kycy7a\/gtao_loading_times_using_different_methods\/\">\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043d\u0435<\/a>). \u041f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0439 \u043c\u0435\u0440\u0435, \u0437\u043d\u0430\u0447\u0438\u043c\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u044f \u043d\u0435 \u0437\u0430\u043c\u0435\u0442\u0438\u043b.<\/p>\n<h3 id=\"ia-takoi-ne-odin\">\u042f \u0442\u0430\u043a\u043e\u0439 (\u043d\u0435) \u043e\u0434\u0438\u043d<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0435\u0440\u0438\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.reddit.com\/r\/gtaonline\/comments\/ht4i56\/your_average_online_loading_time\/\">\u044d\u0442\u043e\u043c\u0443 \u043e\u043f\u0440\u043e\u0441\u0443<\/a>, \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0440\u0430\u0437\u0434\u0440\u0430\u0436\u0430\u044e\u0442 \u0431\u043e\u043b\u0435\u0435 80% \u0430\u0443\u0434\u0438\u0442\u043e\u0440\u0438\u0438 \u0438\u0433\u0440\u044b. \u0418 \u0442\u0430\u043a \u0443\u0436\u0435 \u0441\u0435\u043c\u044c \u043b\u0435\u0442, Rockstar!<\/p>\n<figure class=\"border\">\n<img src=\"survey.png\" \/>\n<\/figure>\n<p>\u041f\u043e\u043a\u043e\u043f\u0430\u0432\u0448\u0438\u0441\u044c \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0432 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u0442\u0435\u0445 20% \u0441\u0447\u0430\u0441\u0442\u043b\u0438\u0432\u0447\u0438\u043a\u043e\u0432, \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u0437\u0430 3 \u043c\u0438\u043d\u0443\u0442\u044b \u0438\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435, \u044f <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=pJzr3qfyCyg\">\u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b<\/a> <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=RK7BUFx_NGk\">\u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0438<\/a>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0442\u043e\u043f\u043e\u0432\u044b\u0435 \u041f\u041a \u0433\u0440\u0443\u0437\u044f\u0442 \u0438\u0433\u0440\u0443 \u0437\u0430 2-\u0441-\u0433\u0430\u043a\u043e\u043c \u043c\u0438\u043d\u0443\u0442\u044b. \u042f \u0431\u044b \u0441\u0434\u0435\u043b\u0430\u043b \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e <em>(\u0441 \u0438\u0433\u0440\u043e\u0439)<\/em> \u0440\u0430\u0434\u0438 \u0442\u0430\u043a\u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u044b\u0445 \u0437\u0430\u0433\u0440\u0443\u0437\u043e\u043a! \u0418 \u0432\u0441\u0435-\u0442\u0430\u043a\u0438, \u0445\u043e\u0442\u044f \u0432\u0440\u0435\u043c\u044f \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0436\u0435\u043b\u0435\u0437\u0430, \u0447\u0442\u043e-\u0442\u043e \u0441 \u043d\u0438\u043c \u043d\u0435\u043b\u0430\u0434\u043d\u043e...<\/p>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430 \u0434\u0430\u0436\u0435 \u043d\u0430 \u0442\u043e\u043f\u043e\u0432\u044b\u0445 \u041f\u041a \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0441\u0435 \u0435\u0449\u0435 \u043e\u043a\u043e\u043b\u043e \u043c\u0438\u043d\u0443\u0442\u044b? \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0436\u0435 \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0438\u0437 \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430 \u0432 \u0441\u0435\u0442\u0435\u0432\u043e\u0439. \u042f \u0437\u043d\u0430\u044e, \u0447\u0442\u043e \u043c\u043e\u0439 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440 \u043d\u0435 \u0441\u0430\u043c\u044b\u0439 \u0431\u044b\u0441\u0442\u0440\u044b\u0439, \u043d\u043e \u043d\u0435 \u0432 \u043f\u044f\u0442\u044c \u0436\u0435 \u0440\u0430\u0437.<\/p>\n<h3 id=\"vysokotochnye-izmereniia\">\u0412\u044b\u0441\u043e\u043a\u043e\u0442\u043e\u0447\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f<\/h3>\n<p>\u0418 \u0442\u0430\u043a, \u0437\u0430\u0440\u0443\u0447\u0438\u0432\u0448\u0438\u0441\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043d\u0435\u0441\u0440\u0430\u0432\u043d\u0435\u043d\u043d\u043e\u0433\u043e <em>\u0414\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 \u0417\u0430\u0434\u0430\u0447<\/em>, \u044f \u043d\u0430\u0447\u0430\u043b \u0441\u0432\u043e\u0435 \u0440\u0430\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<figure class=\"border\">\n<img src=\"task-manager.png\" \/>\n<\/figure>\n<p>\u041e\u0431\u0449\u0438\u0435 \u0434\u043b\u044f \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u043e\u0439 \u0438 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0438\u0433\u0440\u044b \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0438\u0441\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0437\u0430 \u043c\u0438\u043d\u0443\u0442\u0443, \u0447\u0442\u043e \u0441\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438 \u043d\u0430 \u0442\u043e\u043f\u043e\u0432\u044b\u0445 \u041f\u041a. \u041d\u043e \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e GTA \u0432\u0434\u0440\u0443\u0433 \u0440\u0435\u0448\u0438\u043b\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u043c\u0438\u043d\u0443\u0442\u044b \u043f\u043e\u0433\u0440\u0435\u0442\u044c \u0440\u043e\u0432\u043d\u043e \u043e\u0434\u043d\u043e \u044f\u0434\u0440\u043e \u043c\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430.<\/p>\n<p>\u0414\u0438\u0441\u043a\u043e\u0432\u0430\u044f \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c? \u041d\u043e\u043b\u044c! \u0421\u0435\u0442\u0435\u0432\u0430\u044f \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c? \u041d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f, \u0438 \u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u043d\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u043a\u0443\u043d\u0434, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u043e\u0434\u0433\u0440\u0443\u0437\u043a\u0438 \u0440\u0435\u043a\u043b\u0430\u043c\u043d\u044b\u0445 \u0431\u0430\u043d\u043d\u0435\u0440\u043e\u0432. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f GPU? \u041d\u043e\u043b\u044c. \u041e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438? \u041d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f...<\/p>\n<p>\u0427\u0442\u043e \u0442\u0430\u043c, \u0447\u0435\u0440\u0442 \u0432\u043e\u0437\u043c\u0438, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442? \u041c\u0430\u0439\u043d\u0438\u043d\u0433 \u043a\u0440\u0438\u043f\u0442\u044b? \u042f \u0447\u0443\u044e \u0437\u0430\u043f\u0430\u0445 \u0433\u043e\u0432\u043d\u043e\u043a\u043e\u0434\u0430.<\/p>\n<h3 id=\"odnopotochnost\">\u041e\u0434\u043d\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c<\/h3>\n<p>\u041c\u043e\u0439 \u0432\u043e\u0441\u044c\u043c\u0438\u044f\u0434\u0435\u0440\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u043e\u0442 AMD \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0435\u043f\u043b\u043e\u0445 \u043f\u043e \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u043c\u0435\u0440\u043a\u0430\u043c, \u043d\u043e \u043e\u043d \u0443\u0436\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u0442\u0430\u0440. \u0418\u0437 \u0442\u0435\u0445 \u0432\u0440\u0435\u043c\u0435\u043d, \u043a\u043e\u0433\u0434\u0430 \u0438\u0445 \u043e\u0434\u043d\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/valid.x86.fr\/bench\/6u7sdy\/1\">\u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0442\u0441\u0442\u0430\u0432\u0430\u043b\u0430<\/a> \u043e\u0442 Intel. \u042d\u0442\u043e, \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u043c\u043e\u0433\u043b\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438.<\/p>\n<p>\u041d\u043e \u043f\u043e\u0434\u043e\u0437\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u043e, \u0447\u0442\u043e \u0438\u0433\u0440\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <em>\u0442\u043e\u043b\u044c\u043a\u043e<\/em> \u0426\u041f. \u041d\u0435 \u0434\u0438\u0441\u043a \u0434\u043b\u044f \u043f\u043e\u0434\u0433\u0440\u0443\u0437\u043a\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432. \u041d\u0435 \u0441\u0435\u0442\u044c \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 p2p-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u041e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u044f \u043d\u0430\u0448\u0435\u043b \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0431\u0430\u0433.<\/p>\n<h3 id=\"profilirovanie\">\u041f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n<p>\u041b\u0435\u0433\u0447\u0435 \u0432\u0441\u0435\u0433\u043e \u0438\u0441\u043a\u0430\u0442\u044c \u0433\u043e\u0440\u044f\u0447\u0438\u0435 \u0443\u0447\u0430\u0441\u0442\u043a\u0438 \u043a\u043e\u0434\u0430, \u0432\u043e\u043e\u0440\u0443\u0436\u0438\u0432\u0448\u0438\u0441\u044c \u043f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u043c. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0438\u0437 \u043d\u0438\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u043f\u0443\u0442\u0435\u043c \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u0432\u043d\u0435\u0434\u0440\u044f\u044f\u0441\u044c \u0432 \u043d\u0435\u0435 \u0434\u043e \u0441\u0431\u043e\u0440\u043a\u0438, \u0440\u0430\u0434\u0438 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u0439. \u0410 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0443 \u043c\u0435\u043d\u044f \u043d\u0435\u0442. \u0421 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, <em>\u0442\u043e\u0447\u043d\u044b\u0435<\/em> \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u043c\u043d\u0435 \u0438 \u043d\u0435 \u043d\u0443\u0436\u043d\u044b \u2014 \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0433\u043e\u0440\u044f\u0447\u0438\u0439 \u043a\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043c\u0438\u043d\u0443\u0442\u0430\u043c\u0438.<\/p>\n<p>\u041e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0439 \u0432\u044b\u0445\u043e\u0434 \u0432 \u0442\u0430\u043a\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u2014 \u0441\u044d\u043c\u043f\u043b\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0449\u0438\u043a. \u0422\u0430\u043a\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u0435\u043b\u0430\u044e\u0442 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0434\u0430\u043c\u043f\u044b \u0441\u0442\u0435\u043a\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u0447\u0442\u043e\u0431\u044b \u043f\u043e \u043d\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430. \u042f \u0437\u043d\u0430\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0449\u0438\u043a (\u0445\u043e\u0442\u044f, \u043c\u043e\u0436\u0435\u0442, \u0435\u0441\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e\u0434 Windows. \u0425\u043e\u0442\u044c \u043e\u043d \u0438 \u043d\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u043b\u0441\u044f \u0443\u0436\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u0435\u0441\u044f\u0442\u0438 \u043b\u0435\u0442, <a rel=\"noopener external\" target=\"_blank\" href=\"http:\/\/lukestackwalker.sourceforge.net\/\">Luke Stackwalker<\/a> \u0432\u0441\u0435 \u0435\u0449\u0435 \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u0441\u043b\u043e\u0432\u0430 \u043c\u043e\u0435\u0439 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u043d\u043e\u0441\u0442\u0438.<\/p>\n<figure class=\"border\">\n<img src=\"luke-stackwalker.png\" \/>\n<\/figure>\n<p>\u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, Luke \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0431\u044b \u0432\u044b\u0437\u043e\u0432\u044b \u043e\u0434\u043d\u043e\u0439 \u0438 \u0442\u043e\u0439 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u043e\u0434\u043d\u0443 \u0437\u0430\u043f\u0438\u0441\u044c. \u041d\u043e \u0443 \u043c\u0435\u043d\u044f \u043d\u0435\u0442 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u0434\u043b\u044f GTA Online, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0441\u044f \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0441\u0430\u043c \u043d\u0430 \u0442\u0435 \u0430\u0434\u0440\u0435\u0441\u0430, \u0447\u0442\u043e \u0440\u044f\u0434\u043e\u043c. \u0418 \u0447\u0442\u043e \u0436\u0435 \u044f \u0443\u0432\u0438\u0434\u0435\u043b? \u041d\u0435 \u043e\u0434\u043d\u043e \u0443\u0437\u043a\u043e\u0435 \u043c\u0435\u0441\u0442\u043e, \u0430 \u0446\u0435\u043b\u044b\u0445 \u0434\u0432\u0430!<\/p>\n<h3 id=\"krolich-ia-nora\">\u041a\u0440\u043e\u043b\u0438\u0447\u044c\u044f \u043d\u043e\u0440\u0430<\/h3>\n<p><em>\u041e\u0434\u043e\u043b\u0436\u0438\u0432 \u0443 \u043f\u0440\u0438\u044f\u0442\u0435\u043b\u044f<\/em> \u0435\u0433\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043b\u0435\u0433\u0430\u043b\u044c\u043d\u0443\u044e \u043a\u043e\u043f\u0438\u044e <em>\u0432\u0441\u0435\u043c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u0434\u0438\u0437\u0430\u0441\u0441\u0435\u043c\u0431\u043b\u0435\u0440\u0430<\/em> (\u043d\u0430\u0434\u043e \u0442\u0430\u043a\u0438 \u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/ghidra-sre.org\/\">ghidra<\/a>), \u044f \u043f\u0440\u0438\u043d\u044f\u043b\u0441\u044f \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c GTA \u043d\u0430 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<figure class=\"border\">\n<img src=\"disassembly-1.png\" \/>\n<\/figure>\n<p>\u0425\u043c, \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u0442\u043e. \u041f\u043e\u0445\u043e\u0436\u0435, \u0447\u0442\u043e \u043a\u043e\u0434 \u043e\u0431\u0444\u0443\u0441\u0446\u0438\u0440\u043e\u0432\u0430\u043d, \u043a\u0430\u043a \u0438 \u0443 \u043c\u043d\u043e\u0433\u0438\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 AAA-\u0432\u0438\u0434\u0435\u043e\u0438\u0433\u0440. \u0427\u0442\u043e \u0436, \u043d\u0430\u043c \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043d\u0430\u043c \u043a\u043e\u0434 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438\u0437 \u043f\u0430\u043c\u044f\u0442\u0438 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u0439 \u0438\u0433\u0440\u044b. \u0420\u0430\u043d\u043e \u0438\u043b\u0438 \u043f\u043e\u0437\u0434\u043d\u043e \u0435\u0439 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0438\u0445 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u041e\u0442\u043a\u043e\u043f\u0430\u0432 \u0432 \u0441\u0432\u043e\u0438\u0445 \u0437\u0430\u043a\u0440\u043e\u043c\u0430\u0445 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/glmcdona\/Process-Dump\">Process Dump<\/a>, \u044f \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b \u043a\u043e\u0435-\u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435.<\/p>\n<h3 id=\"problema-raz-strlen\">\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0440\u0430\u0437: ...<code>strlen<\/code>?!<\/h3>\n<p>\u0414\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \"\u0433\u043e\u0440\u044f\u0447\u0438\u0445\" \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0434\u0438\u0437\u0430\u0441\u0441\u0435\u043c\u0431\u043b\u0435\u0440 \u0432\u044b\u0442\u044f\u043d\u0443\u043b \u043e\u0442\u043a\u0443\u0434\u0430-\u0442\u043e \u0438\u043c\u044f! \u0418 \u044d\u0442\u043e\u2026 <code>strlen<\/code>? \u0412\u044b\u0448\u0435 \u043f\u043e \u0441\u0442\u0435\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <code>vscan_fn<\/code>, \u0430 \u0435\u0435, \u044f \u043f\u043e\u0447\u0442\u0438 \u0443\u0432\u0435\u0440\u0435\u043d, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/chakra-core\/ChakraCore\/blob\/master\/pal\/src\/safecrt\/sscanf.c#L47\"><code>sscanf<\/code><\/a>.<\/p>\n<figure class=\"border\">\n<img src=\"disassembly-2.png\" \/>\n<\/figure>\n<p>\u041f\u043e\u0445\u043e\u0436\u0435, \u0438\u0433\u0440\u0430 \u0447\u0442\u043e-\u0442\u043e \u043f\u0430\u0440\u0441\u0438\u0442. \u041d\u043e \u0447\u0442\u043e? \u0420\u0430\u0441\u043f\u0443\u0442\u044b\u0432\u0430\u044f \u0432\u044b\u0432\u043e\u0434 \u0434\u0438\u0437\u0430\u0441\u0441\u0435\u043c\u0431\u043b\u0435\u0440\u0430, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0435\u0447\u043d\u043e\u0441\u0442\u044c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043b \u043f\u0430\u0440\u0443 \u0434\u0430\u043c\u043f\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>x64dbg<\/code>. \u0418 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u043f\u0430\u0440\u0441\u0438\u0442\u0441\u044f\u2026 JSON! \u0414\u0430, \u0441\u0430\u043c\u044b\u0439 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 JSON. \u0415\u0441\u043b\u0438 \u0431\u044b\u0442\u044c \u0442\u043e\u0447\u043d\u0435\u0435, <em>10 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442<\/em> JSON-\u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0441 63 \u0442\u044b\u0441\u044f\u0447\u0430\u043c\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"json\"><span class=\"giallo-l\"><span class=\"z-source\">...,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">key<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">WP_WCT_TINT_21_t2_v9_n2<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">price<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 45000<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">statName<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">CHAR_KIT_FM_PURCHASE20<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">storageType<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation z-definition z-string\"> &quot;<\/span><span class=\"z-string\">BITFIELD<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">bitShift<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 7<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">bitSize<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">    &quot;<\/span><span class=\"z-support z-type z-property-name z-json\">category<\/span><span class=\"z-punctuation\">&quot;<\/span><span class=\"z-punctuation\">:<\/span><span class=\"z-punctuation\"> [<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-string\">CATEGORY_WEAPON_MOD<\/span><span class=\"z-punctuation z-definition z-string\">&quot;<\/span><span class=\"z-punctuation\">]<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\">,<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">...<\/span><\/span><\/code><\/pre>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u044e, \u044d\u0442\u043e \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0432\u0435\u0449\u0435\u0439 \u0438 \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u043e\u0432, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043a \u043f\u043e\u043a\u0443\u043f\u043a\u0438 \u0432 GTA Online \u0437\u0430 \u0432\u043d\u0443\u0442\u0440\u0438\u0438\u0433\u0440\u043e\u0432\u0443\u044e \u0432\u0430\u043b\u044e\u0442\u0443.<\/p>\n<p>\u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u0441\u043a\u0430\u0436\u0435\u0442\u0435 \u0432\u044b, 10 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442 \u2014 \u043d\u0435 \u0442\u0430\u043a \u0443\u0436 \u0438 \u043c\u043d\u043e\u0433\u043e. \u0418 <code>sscanf<\/code> \u2014 \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043d\u0435 \u043b\u0443\u0447\u0448\u0438\u0439 \u0432\u044b\u0431\u043e\u0440, \u043d\u043e \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0436\u0435 \u0432\u0441\u0435 \u0431\u044b\u0442\u044c \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u043e\u0445\u043e? \u0427\u0442\u043e \u0436...<\/p>\n<figure class=\"border\">\n<img src=\"flowchart.png\" \/>\n<\/figure>\n<p>\u041c\u0434\u0430, \u043d\u0435 \u0441\u0430\u043c\u044b\u0439 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c. \u0427\u0435\u0441\u0442\u043d\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u044f \u0438 \u0441\u0430\u043c \u043d\u0435 \u0437\u043d\u0430\u043b, \u0447\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439 <code>sscanf<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f <code>strlen<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0432\u0438\u043d\u044e \u0442\u043e\u0433\u043e, \u043a\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u044d\u0442\u043e\u0442 \u043a\u043e\u0434. \u042f \u0434\u0443\u043c\u0430\u043b, \u0447\u0442\u043e <code>sscanf<\/code> \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0438\u0442\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0431\u0430\u0439\u0442\u043e\u0432\u043e, \u043f\u043e\u043a\u0430 \u043d\u0435 \u043d\u0430\u0442\u043a\u043d\u0435\u0442\u0441\u044f \u043d\u0430 <code>'\\0'<\/code>.<\/p>\n<h3 id=\"problema-dva-khesh-spiski\">\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0434\u0432\u0430: \u0445\u044d\u0448-\u2026 \u0441\u043f\u0438\u0441\u043a\u0438?<\/h3>\n<p>\u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u043d\u043e\u0432\u043d\u0438\u043a \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0432\u0441\u0435\u043c \u0440\u044f\u0434\u043e\u043c. \u0412 \u0434\u0435\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0435 \u043d\u0438\u0436\u0435 \u043e\u043d\u0438 \u0432 \u043e\u0434\u043d\u043e\u043c \u0438 \u0442\u043e\u043c \u0436\u0435 \u0431\u043b\u043e\u043a\u0435 <code>if<\/code>.<\/p>\n<figure class=\"border\">\n<img src=\"disassembly-3.png\" \/>\n<\/figure>\n<p>\u0412\u0441\u0435 \u0438\u043c\u0435\u043d\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043c\u043e\u0435\u0433\u043e \u0430\u0432\u0442\u043e\u0440\u0441\u0442\u0432\u0430. \u041d\u0435 \u0438\u043c\u0435\u044e \u043f\u043e\u043d\u044f\u0442\u0438\u044f, \u043a\u0430\u043a \u043e\u043d\u0438 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435.<\/p>\n<p>\u0412\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u0442\u0440\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435. \u041a\u0430\u0436\u0434\u044b\u0439 \u0435\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a, \u043a\u0430\u043a \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u043d\u0438\u0436\u0435. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u044d\u0442\u043e \u0442\u043e, \u0432\u043e \u0447\u0442\u043e \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0432\u044f\u0437\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437 C++? \u042f \u043d\u0435 \u0437\u043d\u0430\u044e \u0442\u043e\u0447\u043d\u043e.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">struct<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">    uint64_t<\/span><span class=\"z-source\">  hash<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-support z-type\">    item_t<\/span><span class=\"z-keyword z-operator\">   *<\/span><span class=\"z-source\">item<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><span class=\"z-source\"> entry<\/span><span class=\"z-punctuation\">;<\/span><\/span><\/code><\/pre>\n<p>\u041d\u043e \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u0438\u0433\u0440\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442 \u0432\u0441\u0435 \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0435\u0441\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043d\u0430 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0445\u044d\u0448\u0430. \u0421 63 \u0442\u044b\u0441\u044f\u0447\u0430\u043c\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u044d\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 <code>(n^2+n)\/2 = (63000^2+63000)\/2 = 1984531500<\/code> \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0439. \u0418 \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0438\u0445 \u0447\u0430\u0441\u0442\u044c \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u0430 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u0430. \u0423 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c <em>\u0445\u044d\u0448\u0438<\/em>, \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <em>\u0445\u044d\u0448<\/em>-\u0442\u0430\u0431\u043b\u0438\u0446\u0443?<\/p>\n<figure class=\"border\">\n<img src=\"disassembly-4.png\" \/>\n<\/figure>\n<p>\u0412 \u0434\u0435\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u0445 \u044f \u043d\u0430\u0437\u0432\u0430\u043b \u044d\u0442\u043e <code>hashmap<\/code>, \u0445\u043e\u0442\u044f \u0441\u0442\u043e\u0438\u043b\u043e \u0431\u044b \u043d\u0430\u0437\u0432\u0430\u0442\u044c <code>clearly_not_a_hashmap<\/code>. \u041d\u043e \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0432\u0441\u0435 \u0435\u0449\u0435 \u0432\u0435\u0441\u0435\u043b\u0435\u0435. \u041f\u0435\u0440\u0435\u0434 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439 JSON, \u044d\u0442\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0443\u0441\u0442\u0430. \u0410 \u0432 \u0441\u0430\u043c\u043e\u043c JSON \u0432\u0441\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b! \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0445\u044d\u0448\u0435\u0439 \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 <em>\u043d\u0435 \u043d\u0443\u0436\u043d\u044b<\/em>! \u0423 \u043d\u0438\u0445 \u0434\u0430\u0436\u0435 \u0435\u0441\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0431\u0435\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a! WTF?!<\/p>\n<h3 id=\"proof-of-concept\">Proof-of-concept<\/h3>\n<p>\u042d\u0442\u043e \u0432\u0441\u0435, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432\u0435\u0441\u0435\u043b\u043e, \u043d\u043e \u0434\u043b\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043a\u043b\u0438\u043a\u0431\u0435\u0439\u0442\u043d\u043e\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0438\u043a\u0441.<\/p>\n<p>\u041f\u043b\u0430\u043d \u0431\u044b\u043b \u0442\u0430\u043a\u043e\u0439: \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c <code>.dll<\/code>, \u0438\u043d\u0436\u0435\u043a\u0442\u043d\u0443\u0442\u044c \u0435\u0435 \u0432 GTA, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/TsudaKageyu\/minhook\">\u0445\u0443\u043a\u0438<\/a>, ???, profit.<\/p>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441 JSON \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d\u0430. \u042f \u043d\u0435 \u043c\u043e\u0433 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u0441\u0435\u0440 \u0431\u0435\u0437 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439. \u0411\u043e\u043b\u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 \u043f\u043e\u0434\u043c\u0435\u043d\u0438\u0442\u044c <code>sscanf<\/code> \u043d\u0430 \u0447\u0442\u043e-\u0442\u043e, \u0447\u0442\u043e \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <code>strlen<\/code>. \u041d\u043e \u044f \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u043b \u0435\u0449\u0435 \u043f\u0440\u043e\u0449\u0435: \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043b \u0445\u0443\u043a \u043d\u0430 <code>strlen<\/code>, \u0438 \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043b \u0435\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u0438\u043d\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a. \u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u044d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">size_t<\/span><span class=\"z-entity z-name z-function\"> strlen_cacher<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-type\">char<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> str<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  static<\/span><span class=\"z-storage z-type\"> char<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-source\"> start<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  static<\/span><span class=\"z-storage z-type\"> char<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-source\"> end<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  size_t<\/span><span class=\"z-source\"> len<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-modifier\">  const<\/span><span class=\"z-storage z-type\"> size_t<\/span><span class=\"z-source\"> cap <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-constant z-numeric\"> 20000<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u0432 &quot;\u043a\u044d\u0448\u0435&quot; \u0435\u0441\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0430, \u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u0433\u0434\u0435-\u0442\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-source\">start <\/span><span class=\"z-keyword z-operator\">&amp;&amp;<\/span><span class=\"z-source\"> str <\/span><span class=\"z-keyword z-operator\">&gt;=<\/span><span class=\"z-source\"> start <\/span><span class=\"z-keyword z-operator\">&amp;&amp;<\/span><span class=\"z-source\"> str <\/span><span class=\"z-keyword z-operator\">&lt;=<\/span><span class=\"z-source\"> end<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0434\u043b\u0438\u043d\u0443<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    len <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> end <\/span><span class=\"z-keyword z-operator\">-<\/span><span class=\"z-source\"> str<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u0435\u0441\u043b\u0438 \u043c\u044b \u0440\u044f\u0434\u043e\u043c \u0441 \u043a\u043e\u043d\u0446\u043e\u043c \u0441\u0442\u0440\u043e\u043a\u0438, \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0445\u0443\u043a<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">    \/\/<\/span><span class=\"z-comment\"> \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043d\u0430\u043f\u043e\u0440\u0442\u0430\u0447\u0438\u0442\u044c \u043d\u0435\u043d\u0430\u0440\u043e\u043a\u043e\u043c<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    if<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-source\">len <\/span><span class=\"z-keyword z-operator\">&lt;<\/span><span class=\"z-source\"> cap <\/span><span class=\"z-keyword z-operator\">\/<\/span><span class=\"z-constant z-numeric\"> 2<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">      MH_DisableHook<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">LPVOID<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-source\">strlen_addr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-source\"> len<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 strlen<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0445\u043e\u0442\u044f \u0431\u044b \u0440\u0430\u0437 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0433\u043e JSON<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">  len <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-entity z-name z-function\"> builtin_strlen<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">str<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0435\u0441\u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0430 \u0431\u044b\u043b\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u0438\u043d\u043d\u043e\u0439<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438 \u043d\u0430 \u043d\u0430\u0447\u0430\u043b\u043e \u0438 \u043a\u043e\u043d\u0435\u0446<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-source\">len <\/span><span class=\"z-keyword z-operator\">&gt;<\/span><span class=\"z-source\"> cap<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    start <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> str<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-source\">    end <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> str <\/span><span class=\"z-keyword z-operator\">+<\/span><span class=\"z-source\"> len<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-source\"> len<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p>\u0421 \"\u0445\u044d\u0448-\u0441\u043f\u0438\u0441\u043a\u043e\u043c\" \u0432\u0441\u0435 \u043f\u0440\u043e\u0449\u0435: \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0441\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0445 \u0431\u0435\u0437 \u0432\u0441\u044f\u043a\u0438\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a.<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"cpp\"><span class=\"giallo-l\"><span class=\"z-storage z-type\">char<\/span><span class=\"z-storage z-type\"> __fastcall<\/span><span class=\"z-entity z-name z-function\"> netcat_insert_dedupe_hooked<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-type\">uint64_t<\/span><span class=\"z-variable z-parameter\"> catalog<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-type\"> uint64_t<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> key<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-storage z-type\"> uint64_t<\/span><span class=\"z-storage z-modifier\">*<\/span><span class=\"z-variable z-parameter\"> item<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">{<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u044f \u0437\u0430\u0431\u0438\u043b \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0432\u0435\u0440\u0441\u0438\u0442\u044c \u0432\u0441\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-storage z-type\">  uint64_t<\/span><span class=\"z-source\"> not_a_hashmap <\/span><span class=\"z-keyword z-operator\">=<\/span><span class=\"z-source\"> catalog <\/span><span class=\"z-keyword z-operator\">+<\/span><span class=\"z-constant z-numeric\"> 88<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0445\u0437, \u0447\u0442\u043e \u044d\u0442\u043e, \u043d\u043e \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0432 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u0435<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-keyword z-operator\">!<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-type\">uint8_t<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">__fastcall<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-storage z-type\">uint64_t<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-source\">item <\/span><span class=\"z-keyword z-operator\">+<\/span><span class=\"z-constant z-numeric\"> 48<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">item<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">)<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">    return<\/span><span class=\"z-constant z-numeric\"> 0<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0431\u0435\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">  netcat_insert_direct<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">not_a_hashmap<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-source\"> key<\/span><span class=\"z-punctuation\">,<\/span><span class=\"z-keyword z-operator\"> &amp;<\/span><span class=\"z-source\">item<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation z-definition z-comment\">  \/\/<\/span><span class=\"z-comment\"> \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0445\u0443\u043a \u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u0442\u044c .dll<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  if<\/span><span class=\"z-punctuation\"> (<\/span><span class=\"z-keyword z-operator\">*<\/span><span class=\"z-source\">key <\/span><span class=\"z-keyword z-operator\">==<\/span><span class=\"z-keyword\"> 0x<\/span><span class=\"z-constant z-numeric\">7FFFD6BE<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\"> {<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    MH_DisableHook<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-source\">LPVOID<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-source\">netcat_insert_dedupe_addr<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-entity z-name z-function\">    unload<\/span><span class=\"z-punctuation\">(<\/span><span class=\"z-punctuation\">)<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">  }<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span class=\"z-keyword\">  return<\/span><span class=\"z-constant z-numeric\"> 1<\/span><span class=\"z-punctuation\">;<\/span><\/span>\n<span class=\"giallo-l\"><span class=\"z-punctuation\">}<\/span><\/span><\/code><\/pre>\n<p><a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/github.com\/tostercx\/GTAO_Booster_PoC\">\u041f\u043e\u043b\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0437\u0434\u0435\u0441\u044c.<\/a><\/p>\n<h3 id=\"rezul-taty\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b<\/h3>\n<p>\u0421\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u043b\u0438?<\/p>\n<pre class=\"giallo z-code\"><code data-lang=\"plain\"><span class=\"giallo-l\"><span>Original online mode load time:        ~6m flat<\/span><\/span>\n<span class=\"giallo-l\"><span>Time with only duplication check patch: 4m 30s<\/span><\/span>\n<span class=\"giallo-l\"><span>Time with only JSON parser patch:       2m 50s<\/span><\/span>\n<span class=\"giallo-l\"><span>Time with both issues patched:          1m 50s<\/span><\/span>\n<span class=\"giallo-l\"><\/span>\n<span class=\"giallo-l\"><span>(6*60 - (1*60+50)) \/ (6*60) = 69.4% load time improvement (nice!)<\/span><\/span><\/code><\/pre>\n<p>\u0414\u0430, \u0447\u0435\u0440\u0442 \u0432\u043e\u0437\u044c\u043c\u0438!<\/p>\n<p>\u042d\u0442\u043e\u0442 \u0444\u0438\u043a\u0441 \u043f\u043e\u0447\u0442\u0438 \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u043d\u0435 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442 \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439. \u041d\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u0443\u0437\u043a\u0438\u0435 \u043c\u0435\u0441\u0442\u0430 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u043c\u0438. \u041d\u043e \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0435 \u043c\u043d\u043e\u0439 \u0432\u0435\u0449\u0438 \u0431\u044b\u043b\u0438 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b, \u0447\u0442\u043e \u044f \u043d\u0435 \u0437\u043d\u0430\u044e, \u043f\u043e\u0447\u0435\u043c\u0443 Rockstar \u0438\u0445 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u043d\u0435 \u043f\u043e\u0444\u0438\u043a\u0441\u0438\u043b\u0438.<\/p>\n<h3 id=\"tl-dr\">TL;DR<\/h3>\n<ul>\n<li>\u041f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 GTA Online \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u044b\u0439 CPU-\u0431\u043e\u0442\u0442\u043b\u043d\u0435\u043a<\/li>\n<li>\u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e GTA \u0434\u043e\u043b\u0433\u043e \u0438 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e \u0447\u0438\u0442\u0430\u0435\u0442 10 \u041c\u0411 JSON-\u0442\u0435\u043a\u0441\u0442\u0430<\/li>\n<li>\u041f\u0430\u0440\u0441\u0435\u0440 JSON \u043d\u0435 \u0441\u0430\u043c\u044b\u0439 \u043b\u0443\u0447\u0448\u0438\u0439 \u0438\u043b\u0438 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043d\u0430\u0438\u0432\u043d\u044b\u0439<\/li>\n<li>\u041f\u043e\u0441\u043b\u0435 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0435\u0441\u0442\u044c \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0430\u044f \u0438 \u043d\u0435\u043d\u0443\u0436\u043d\u0430\u044f \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0430 \u0434\u0435\u0434\u0443\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u0438<\/li>\n<\/ul>\n<h3 id=\"r-please-fix\">R* please fix<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u0447\u0438\u0442\u0430\u0435\u0442 \u043a\u0442\u043e-\u0442\u043e \u0438\u0437 Rockstar: \u044d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0442\u0430\u043a \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e\u0444\u0438\u043a\u0441\u0438\u0442\u044c. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0441\u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c.<\/p>\n<p>\u0414\u043b\u044f \u0434\u0435\u0434\u0443\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0445\u044d\u0448-\u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0438\u043b\u0438 \u0436\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0442 \u043d\u0435\u0435 \u043e\u0442\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f. \u041f\u0430\u0440\u0441\u0435\u0440 JSON \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u0431\u044b\u0441\u0442\u0440\u044b\u0439. \u042d\u0442\u043e \u043d\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u043e\u0436\u043d\u044b\u043c.<\/p>\n<p>\u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u043f\u0430\u0441\u0438\u0431\u043a\u0438 &lt;3<\/p>\n"},{"title":"(\u041f\u0435\u0440\u0435\u0432\u043e\u0434) \u0421\u043e\u0440\u0442\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 (element kinds) \u0432 \u0434\u0432\u0438\u0436\u043a\u0435 V8","published":"2020-11-20T00:00:00+00:00","updated":"2020-11-20T00:00:00+00:00","author":{"name":"Ilia Pozdnyakov","uri":"https:\/\/iliazeus.lol","email":"iliazeus@proton.me"},"link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/iliazeus.lol\/translations\/v8-element-kinds\/"}},"id":"https:\/\/iliazeus.lol\/translations\/v8-element-kinds\/","summary":"<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u043c\u0435\u043d\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 JavaScript-\u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430. \u041d\u043e \u0434\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432 \u0438\u043c\u0435\u043d \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 JavaScript-\u0434\u0432\u0438\u0436\u043a\u0430\u0445. \u041e\u0434\u043d\u0438\u043c \u0438\u0437 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0435 <a rel=\"noopener external\" target=\"_blank\" href=\"https:\/\/tc39.es\/ecma262\/#array-index\">\u0438\u043d\u0434\u0435\u043a\u0441\u044b \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432<\/a>.<\/p>\n<p>\u0425\u043e\u0442\u044f \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0432\u0435\u0434\u0443\u0442 \u0441\u0435\u0431\u044f \u043d\u0435\u043e\u0442\u043b\u0438\u0447\u0438\u043c\u043e \u043e\u0442 \u043b\u044e\u0431\u044b\u0445 \u0434\u0440\u0443\u0433\u0438\u0445, \u0434\u0432\u0438\u0436\u043e\u043a V8, \u0432 \u0446\u0435\u043b\u044f\u0445 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438, \u0445\u0440\u0430\u043d\u0438\u0442 \u0438\u0445 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0441\u043e\u0431\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c. \u0412\u043d\u0443\u0442\u0440\u0438 V8 \u0442\u0430\u043a\u0438\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 <em>\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 (elements)<\/em> \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u0414\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043b\u043e\u0433\u0438\u0447\u043d\u043e: \u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u043f\u043e \u0438\u043c\u0435\u043d\u0438, \u0430 \u0443 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432 \u0435\u0441\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u043f\u043e \u0438\u043d\u0434\u0435\u043a\u0441\u0443.<\/p>"}]}