diff --git a/404.html b/404.html index 5e2fc56..9c7615b 100644 --- a/404.html +++ b/404.html @@ -5,8 +5,8 @@ Page Not Found | Denny's blog - - + +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

diff --git a/assets/images/beekeeper-beaeade119f66325a55e6f5ae21ef953.png b/assets/images/beekeeper-beaeade119f66325a55e6f5ae21ef953.png new file mode 100644 index 0000000..a45063b Binary files /dev/null and b/assets/images/beekeeper-beaeade119f66325a55e6f5ae21ef953.png differ diff --git a/assets/images/git-c137585a8a0b1af52301455de126177b.png b/assets/images/git-c137585a8a0b1af52301455de126177b.png new file mode 100644 index 0000000..f0303ae Binary files /dev/null and b/assets/images/git-c137585a8a0b1af52301455de126177b.png differ diff --git a/assets/js/0c073a7b.7ad4fdf4.js b/assets/js/0c073a7b.f2fcad0b.js similarity index 75% rename from assets/js/0c073a7b.7ad4fdf4.js rename to assets/js/0c073a7b.f2fcad0b.js index a6dcd53..75c4ba2 100644 --- a/assets/js/0c073a7b.7ad4fdf4.js +++ b/assets/js/0c073a7b.f2fcad0b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[445],{124:e=>{e.exports=JSON.parse('[{"label":"software","permalink":"/mynameis/blog/tags/software","count":3},{"label":"career","permalink":"/mynameis/blog/tags/career","count":1}]')}}]); \ No newline at end of file +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[445],{124:e=>{e.exports=JSON.parse('[{"label":"software","permalink":"/mynameis/blog/tags/software","count":4},{"label":"career","permalink":"/mynameis/blog/tags/career","count":1}]')}}]); \ No newline at end of file diff --git a/assets/js/15e7fec8.0ce20a00.js b/assets/js/15e7fec8.0ce20a00.js new file mode 100644 index 0000000..00cf431 --- /dev/null +++ b/assets/js/15e7fec8.0ce20a00.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[872],{6103:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>s,default:()=>m,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var a=n(5893),i=n(1151);const o={slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},s=void 0,r={permalink:"/mynameis/blog/tq-devlog-1",source:"@site/blog/05-tq-devlog-1/index.md",title:"PaaS devlog |#1",description:"Devlog |#1",date:"2024-09-03T18:48:09.000Z",formattedDate:"September 3, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.295,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},unlisted:!1,nextItem:{title:"PaaS devlog |#0",permalink:"/mynameis/blog/tq-devlog-0"}},d={authorsImageUrls:[void 0]},l=[{value:"Devlog |#1",id:"devlog-1",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h2:"h2",img:"img",p:"p",pre:"pre",strong:"strong",...(0,i.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"devlog-1",children:"Devlog |#1"}),"\n",(0,a.jsx)(t.p,{children:"Another day I actually started working on the project (what a surprise)."}),"\n",(0,a.jsx)(t.p,{children:"I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more."}),"\n",(0,a.jsx)(t.p,{children:"Im convinced I will store my data in postgres, therefore I need a local instance, migrations, a tool to lookup the data."}),"\n",(0,a.jsx)(t.p,{children:"First, docker compose. I can't imagine local environment without it. Very simple one, some volumes, passwordless acceess, expose 5432 port, done."}),"\n",(0,a.jsx)(t.p,{children:"I didn't know how my first feature will look like, a user creating, connecting a repository or saving the infrastracture state.\nBut I needed a first migration to test it, so I created a users table. Very creative, but I really will need users table, it's fine."}),"\n",(0,a.jsx)(t.p,{children:"I installed a few dependencies:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-shell",children:"go get github.com/golang-migrate/migrate/v4\ngo get github.com/jmoiron/sqlx\ngo get github.com/jackc/pgx\n"})}),"\n",(0,a.jsx)(t.p,{children:"I will sqlx + squirrel for query executing, pgx as a driver and migrate for running migrations, it prodes cli interface if you want to run in the jobs and go api as well."}),"\n",(0,a.jsx)(t.p,{children:"I will use go api, but I wouldn't recomment it in production, it's important to create a database backup before starting a mgiration, so the best case you have a migration job that makes a backup and then runs the migration, if it worked out - release is welcome."}),"\n",(0,a.jsx)(t.p,{children:"Then I made a few commands to work with migration like create new, up, down and fix migration."}),"\n",(0,a.jsx)(t.admonition,{type:"note",children:(0,a.jsxs)(t.p,{children:["Migration package stores the state in the same database. When it fails it writes the migration as ",(0,a.jsx)(t.code,{children:"dirty"}),". Fix command is used to force the version, it's very useful in the development process. I even used it in prod."]})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-makefile",children:'DB_DSN ?= "postgres://postgres@localhost:5432/tq?sslmode=disable"\n\nmigrate_new:\n migrate create -ext sql -dir migrations -seq -digits 4 ${MNAME}\n\nmigrate_up:\n migrate -path migrations -database ${DB_DSN} up\n\nmigrate_down:\n migrate -path migrations -database ${DB_DSN} down\n\nmigrate_fix:\n migrate -path migrations -database ${DB_DSN} force ${V}\n\nmigrate_v:\n migrate -path migrations -database ${DB_DSN} version\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Using command ",(0,a.jsx)(t.code,{children:"make migrate_new users_table"})," I create a new migration and feel it with the following sql:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-sql",children:'CREATE EXTENSION IF NOT EXISTS "uuid-ossp";\n\nCREATE TABLE IF NOT EXISTS users (\n id uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,\n email varchar(85) NOT NULL,\n password varchar(255) NOT NULL,\n\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL\n);\n'})}),"\n",(0,a.jsx)(t.p,{children:"I like using uuid as an identity. It never fooled me."}),"\n",(0,a.jsx)(t.p,{children:"Then I do what I didn't recommend."}),"\n",(0,a.jsx)(t.p,{children:"Yes, I run the migrations right in the starting the app server.\nSeems ok, applied."}),"\n",(0,a.jsx)(t.p,{children:"I need something to see the result, the table, the extension.\nI use psql, but to me personnaly it's very annoying having such long interface, it matters a lot when I have a few databases to follow."}),"\n",(0,a.jsxs)(t.p,{children:["I looked for a tool again. I tried pgadmin, jetbrains embedded one.\nAnd I found Beekeeper. That's the tool I wouldn't be ashamed to create. Looks very good, easy to use, to edit, look for data with 0 sql, comfortable keyboard control.\nEverything I like.\n",(0,a.jsx)(t.strong,{children:"It's even opensourced and has a free community edition."})]}),"\n",(0,a.jsx)(t.p,{children:"I looked at the data, the migration record exists, the users table does as well."}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(3114).Z+"",width:"697",height:"485"})}),"\n",(0,a.jsxs)(t.p,{children:["Finally I can commit it.\nI like using lazygit for most of my cases.\nIt also a keyboard only control.\nEven my brain can handle it, there are very few commands: arrows to navigate, space to stage a change, you can use mouse to stage only a part of the file, and push ",(0,a.jsx)(t.code,{children:"c"})," to input a commit message and ",(0,a.jsx)(t.code,{children:"Enter"})," to commit.\nIt also has bunch of things like branches list, reflog, command log."]}),"\n",(0,a.jsxs)(t.p,{children:["At least I don't repeatadly do anymore ",(0,a.jsx)(t.code,{children:"ls, gd, ga"})," file by file."]}),"\n",(0,a.jsx)(t.admonition,{type:"note",children:(0,a.jsxs)(t.p,{children:["I use zsh and it gives me many shortcuts, for instance ",(0,a.jsx)(t.code,{children:"ga"})," is equal to ",(0,a.jsx)(t.code,{children:"git add"})]})}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(2772).Z+"",width:"1144",height:"368"})}),"\n",(0,a.jsxs)(t.p,{children:["Thank you for reading, come here and see what's gonna be in the end.\nRepository is here: ",(0,a.jsx)(t.a,{href:"http://github.com/treenq/treenq",children:"http://github.com/treenq/treenq"})]})]})}function m(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},3114:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/beekeeper-beaeade119f66325a55e6f5ae21ef953.png"},2772:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/git-c137585a8a0b1af52301455de126177b.png"},1151:(e,t,n)=>{n.d(t,{Z:()=>r,a:()=>s});var a=n(7294);const i={},o=a.createContext(i);function s(e){const t=a.useContext(o);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),a.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1a1195cb.1314ed7d.js b/assets/js/1a1195cb.1314ed7d.js new file mode 100644 index 0000000..2ebd853 --- /dev/null +++ b/assets/js/1a1195cb.1314ed7d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[531],{7115:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>r,default:()=>c,frontMatter:()=>s,metadata:()=>l,toc:()=>d});var o=n(5893),a=n(1151);const s={slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},r=void 0,l={permalink:"/mynameis/blog/tq-devlog-0",source:"@site/blog/04-tq-devlog-0/index.md",title:"PaaS devlog |#0",description:"Devlog |#0",date:"2024-09-02T20:12:28.000Z",formattedDate:"September 2, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.955,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},unlisted:!1,prevItem:{title:"PaaS devlog |#1",permalink:"/mynameis/blog/tq-devlog-1"},nextItem:{title:"Backend Guy Ventures into Game Development",permalink:"/mynameis/blog/do-gamedev"}},i={authorsImageUrls:[void 0]},d=[{value:"Devlog |#0",id:"devlog-0",level:2}];function m(e){const t={h2:"h2",p:"p",...(0,a.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h2,{id:"devlog-0",children:"Devlog |#0"}),"\n",(0,o.jsx)(t.p,{children:"Today I want to share with you my first steps of creating new project.\nFor a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service."})]})}function c(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(m,{...e})}):m(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>l,a:()=>r});var o=n(7294);const a={},s=o.createContext(a);function r(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1a1195cb.9705aa94.js b/assets/js/1a1195cb.9705aa94.js deleted file mode 100644 index 91eaece..0000000 --- a/assets/js/1a1195cb.9705aa94.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[531],{7115:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>m,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var o=n(5893),a=n(1151);const s={slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},r=void 0,i={permalink:"/mynameis/blog/tq-devlog-0",source:"@site/blog/04-tq-devlog-0/index.md",title:"PaaS devlog |#0",description:"Devlog |#0",date:"2024-09-02T20:12:28.000Z",formattedDate:"September 2, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.91,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},unlisted:!1,nextItem:{title:"Backend Guy Ventures into Game Development",permalink:"/mynameis/blog/do-gamedev"}},l={authorsImageUrls:[void 0]},d=[{value:"Devlog |#0",id:"devlog-0",level:2}];function c(e){const t={h2:"h2",p:"p",...(0,a.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h2,{id:"devlog-0",children:"Devlog |#0"}),"\n",(0,o.jsx)(t.p,{children:"Today I want to share with your my first steps of creating new project.\nFor a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service."})]})}function m(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(c,{...e})}):c(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>i,a:()=>r});var o=n(7294);const a={},s=o.createContext(a);function r(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2e217b76.e8574436.js b/assets/js/2e217b76.fe921355.js similarity index 76% rename from assets/js/2e217b76.e8574436.js rename to assets/js/2e217b76.fe921355.js index 2d4e135..e6b0ab1 100644 --- a/assets/js/2e217b76.e8574436.js +++ b/assets/js/2e217b76.fe921355.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[682],{304:e=>{e.exports=JSON.parse('{"permalink":"/mynameis/blog","page":1,"postsPerPage":10,"totalPages":1,"totalCount":4,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[682],{304:e=>{e.exports=JSON.parse('{"permalink":"/mynameis/blog","page":1,"postsPerPage":10,"totalPages":1,"totalCount":5,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/assets/js/2f6ea139.2aa6cf8c.js b/assets/js/2f6ea139.2aa6cf8c.js deleted file mode 100644 index 2fd36e4..0000000 --- a/assets/js/2f6ea139.2aa6cf8c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[538],{6362:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"tq-devlog-0","metadata":{"permalink":"/mynameis/blog/tq-devlog-0","source":"@site/blog/04-tq-devlog-0/index.md","title":"PaaS devlog |#0","description":"Devlog |#0","date":"2024-09-02T20:12:28.000Z","formattedDate":"September 2, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":3.91,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"tq-devlog-0","title":"PaaS devlog |#0","authors":["denis"],"tags":["software"]},"unlisted":false,"nextItem":{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev"}},"content":"## Devlog |#0\\n\\nToday I want to share with your my first steps of creating new project.\\nFor a long time I\'ve wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service.\\n\\n\x3c!--truncate--\x3e\\n\\nThe main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration.\\nAll the infra will be used from a well known cloud providers (not aws ofc, no clue who can understand how to user it).\\nFirst iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me.\\n\\n### The problem\\n\\nThe technical problem exists, it\'s fun to figure out.\\nBut no the main one. The biggest fight Im gonna accept is __procrastination__. Im such a person who pushes further all the tasks very often. I just have little to do with time discipline. That\'s what will stop me from the progress.\\nSo the easiest way to move progress away - do whatever, but not the progress.\\n\\n### The planing\\n\\nSo I decided to plan everything and understand how big the actual project is gonna be.\\nSo I start speaking with GPT in order to express my mind, kinda talking to a duck. \\nInstead of asking what I should do I explained my plan and asked to ask __more questions__ so it could help me to clarify the technical solution and the plan.\\n\\n![img](./gpt.png)\\n\\n
\\n\\nHere you can find a prompt I used\\n\\nI want to develop a platform like digitalocean app, vercel, render, fly.io, heroku, etc. My value is the following: I give observability with 0 code changes, and a localdev opportunity with connecting to a cloud environment, for instance a request comes from a frontend app on staging to my backend app locally so I could intercept it and make my laptop appear kinda in the cloud. It\'s a multitenant project. There are 2 paths: kubernetes and a custom architecture. To build a custom architecture the app must be on a few virtual machines, a load balancer on top including firewall. The challenge: ask me necessary questions so we could make a right decision. I have to highlight, we build a users\' environment, not the product architecture I will create in order to reproduce the given environment, so we need to decide that would fit me and users better.\\n
\\n\\nInitially I thought I will do it providing a user set of virtual machines connected under VPC, putting a load balancer on top, back to 2000. I thought it will make it cheaper and some tools just easier to implement.\\n\\nChatting to GPT I realized - Kubernetes will provide it a way quicker, most of the stuff is just ready to go like network policies, load balancing, SSL, deployment/rollback, health monitoring, resources observability, Istio adoption. Istio is very useful for observability and local first development, it became a new word today - __remocal__.\\n\\nWhen stepped into the planning I decided to make it even longer.\\nI wanted to researched all the kanban boards, unresistable.\\nI used to use Trello and it was ok, but using api in power-ups boundaries sucks. Not really somethign I need right now though. \\n\\nI tried Cluckup, it\'s a laggish joke, even worse than Jira to make you feel you are already enterprise.\\nI tried Asana and saw 0 difference with Trello, I spent about 2 minutes to confirm it and exist.\\n\\n### The ugly thing\\n\\nIn the end I found Linear. \\nTo be fair it looked ugly, the design is equal to supabase: fonts, buttons.\\n\\nA few minutes later I started catching.\\nKeyboard first design - that\'s what I buy.\\n\\nSo I read Linear Method, the framework they apply internally. It was hard to accept it, I think older I get more conservatibe I become, but I dig it anyway.\\nThe basic element is an issue. It might have sub-issues. And they might have.\\nThey can be collected in a project.\\n\\nThere are bunch of other staff I don\'t use, but I will share it below.\\n- Cycle - like a sprint, hate it.\\n- Triage - inbox, it\'s a boss feature in my opinion, you can aggregate communication channels in a single place, then an on-call person can carry them, create issues or remove.\\n- Initiative - collection of the projects, they can be presented as a time line or a strategy decision, or even a roadmap on a timeline. \\n\\nAs a result I cooked quite a few cards (48 projects in a backlog \ud83d\ude31\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f).\\n\\n![img](./few.png)\\n\\nThank you for reading, come here and see what\'s gonna be in the end.\\nRepository is here: http://github.com/treenq/treenq"},{"id":"do-gamedev","metadata":{"permalink":"/mynameis/blog/do-gamedev","source":"@site/blog/03-do-gamedev/index.mdx","title":"Backend Guy Ventures into Game Development","description":"In order to be engaged one explores different areas and looks for unknown software area.","date":"2024-09-02T18:32:54.000Z","formattedDate":"September 2, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":6.53,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"do-gamedev","title":"Backend Guy Ventures into Game Development","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"PaaS devlog |#0","permalink":"/mynameis/blog/tq-devlog-0"},"nextItem":{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json"}},"content":"In order to be engaged one explores different areas and looks for unknown software area.\\n\\nHere we look at the gamedev in 2024 from experience in server side software.\\n\\nIn software development, it\'s common to explore new domains to stay engaged. \\nWhether it\'s for a change of pace or to push personal boundaries, exploring the unknown can lead to fancy adventures in software. \\nThis page will share my journey as a backend developer diving into the game development in 2024.\\n\\n\x3c!--truncate--\x3e\\n\\n#### Why Gamedev? \\n\\n99% of programmes came here to make a game.\\nEither did I.\\n\\nFrom a young age, I was captivated by two genres: strategy games and action RPGs. \\nMy first PC came preloaded with classics like Red Alert 2, Heroes of Might and Magic 3, and Diablo 2. \\nThe simple yet addictive gameplay\u2014click, move, destroy, enjoy \u2014 cemented my love for these genres. \\nOver the years, I\u2019ve played many iconic RTS games like Warcraft 3 and Starcraft 2 (and still do occasionally).\\nBut I realized that Starcraft 2 and similar games leaned more towards real-time execution rather than strategic depth.\\n\\nSo I decided to make my own game with the strategy and decision making take the center stage.\\n\\n#### Choosing the Game Engine \\n\\nThere are numerous options out there\u2014Defold, RPG Maker, GameMaker, Construct, to name a few.\\n\\nBut I focused on the big three that are free to start with, offer extensive flexibility, and have been tested by major projects: Unreal Engine, Unity, and Godot.\\n\\n#### Unreal Engine: A Mixed Bag of Power and Complexity\\n\\nI chose to start with Unreal Engine. It has a large community, though not the largest. Everything Unity offers in its asset store, Unreal has an equivalent. The engine supports C++ for low-level programming and Blueprints (a visual scripting language) for level design, though you can use either approach.\\n\\nInstalling the engine is a hassle. You need to first install the Epic Games Launcher and then download the 55GB engine itself, which can be a chore if your disk space is limited.\\n\\nAfter setting up a blank project, I was impressed by the vast flexibility Unreal offers. You get all the benefits of C++\u2014dynamic dependency injection, custom components, and more.. But it adds complexity.\\n1. Compiliation time. It exists. Not just exists like a couple blinks 5-10 seconds, it takes a lot of time to build a single class to start using it in the project.\\n2. Code complexity. Write header files, manual memory management. Good package manager doesn\'t exist in 2024, now I understand why they love Rust so much. \\n3. Poor mac support. No comments, even the interface of top bar menu is different, I was struggling to find editor settings according to the documentation, and every question is like that. \\n\\nI would recommend such engine for people who likes waiting, c++ and want to make a beatiful scenes with nice action. \\nI also have to note that engine is open source and owned by a technical guy and people who actually make games. I would stop there if I liked waiting and c++.\\n\\n#### Unity: The Industry Standard.\\n\\nNext up was Unity, the most popular game engine out there. \\nUnity has a vast ecosystem, with advanced features like rendering, post-processing, and easy shader creation. \\nIt\u2019s backed by a huge asset store, which should theoretically make development easier.\\nC# - Im not a big fun, but it\'s compilable, therefore type safe, seems good.\\n\\nA basic abstraction is an object. An object has compenents to manage what is it, it might be a script to move it, a mesh to render a tree, a colission not to pass through the tree, sound to play as tree leafs on the wind and so on.\\nSeems quite simple. \\n\\nBut when I approached a real problem there are plenty of weird things.\\n1. Unity has three different render pipelines, which aren\u2019t compatible with each other. The oldest one is being deprecated, meaning half the assets in the store may soon be obsolete.\\n2. Asset store is a garbage. I tried several camera controllers, and only one partially met my needs. I had to patch it to double its functionality, which felt like reinventing the wheel.\\n\\nWe all remember the Unity pricing drama. It has a closed-source codebase, and now there\u2019s a tracker that counts installations to generate more revenue for shareholders. \\nThis has led to a lot of half-baked features and outdated documentation, which can make the engine feel unstable.\\n\\nUnity is still a solid choice, but in 2024, it feels like the engine is in a weird transitional state. \\nThe documentation isn\u2019t as up-to-date as it should be, and the engine itself seems to be in a half-finished state. \\nI might revisit it in 2025 when Unity 6 is released.\\n\\n#### Godot: Unknown creature in the Sea.\\n\\nFinally, I turned to Godot, an engine I initially underestimated. \\nKnown for its strong 2D capabilities, Godot seemed lacking in 3D support. \\nIts physics engine was also rumored to be subpar.\\n\\nSo I start doing a 3D. \\nFirst I found that asset library is poor, camera controller only for Godot 3 (previous release) and it makes no sense to use Godot 3 in 2024.\\n\\nWhat I actually see in progress.\\n0. Godot\u2019s installation bundle is just 150MB. It has a negligible memory footprint and can run smoothly even on modest hardware. Coming from Unity, this was a breath of fresh air.\\n1. Godot\u2019s editor can be extended in a similar manner to Unity, allowing you to add new UI elements and dynamically instantiate new components.\\n2. The asset library isn\u2019t a store but a repository where everything is distributed for free. Since Godot is open-source, I doubt any significant part of it will go paid, unlike Unity and Unreal, where quality assets often come with a price tag.\\n3. Physics engine implementation can be replaced with jolt easy-peasy and works very well.\\n4. The same abstractions, the same component building, but not an object has component, rather a scene (actually a node) has nodes (the others to implement actual behavior of the node).\\n5. Exporting is just a button click. I managed to build a project for windows in Mac, it\'s so good, haven\'t had such smooth exprerience.\\n\\nIt was surprisingly easy to understand the basics, the nodes design, the event bus system, for a backend guy it\'s perfect to start making a real game.\\n\\nGDScript can fail in runtime, not the best, but you can use C# for the sake of compilte time failure.\\n\\nAnd I know, the community is smaller, it will be developed slower, true. But I care about me today, not the community.\\n\\nI initially planned to give Unity a fair shot, spending a week with both engines. \\nBut after just two days with Godot, I was progressing so much faster that I decided it wasn\u2019t worth the time to continue with Unity. \\nGodot\u2019s lower entry barrier and faster development pace made it the clear choice for me.\\n\\n##### I want to finish simpler. \\n\\nIn the end, the best engine is the one that aligns with your needs and preferences. \\nRemember, Blender was once considered a niche tool while everyone used 3D Max, and now Blender is the industry standard. \\nFirebase was just a \u201cbase,\u201d and today we have Supabase, Pocketbase and many others.\\n\\nThe landscape of game development is always changing. \\nWhat matters most is finding the tool that helps you bring your vision to life, not what the industry standard is. \\nFor me, that tool is Godot.\\n\\n### Lessons\\nSpoiler, no, I didn\'t finish a game, I learned the gamedev abstractions and played with the engines a bit and I enjoyed it.\\nAnd it\'s fine, I had good time and wish everyone to find a toy you can spend some time on and make you engaged."},{"id":"big-json","metadata":{"permalink":"/mynameis/blog/big-json","source":"@site/blog/02-250mbjson-in-50mb-limit/index.mdx","title":"250mb json in a 40mb service limit","description":"This article has been created to remind us of one simple thing: HTTP is a stream.","date":"2024-05-26T15:48:12.000Z","formattedDate":"May 26, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":6.8,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"big-json","title":"250mb json in a 40mb service limit","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev"},"nextItem":{"title":"Why this page exists","permalink":"/mynameis/blog/why-a-blog"}},"content":"This article has been created to remind us of one simple thing: HTTP is a stream.\\n\\nAs a practical outcome we can learn how to reduce memory requirements for our services in a typical task: cache warming.\\n\\n\x3c!--truncate--\x3e\\n\\nLet\'s look at the challenge first.\\n\\nWe have a service that must download the data and keep it in memory.\\nThe issue is the JSON document we have to download is 10 times larger than the encoded data. \\nTherefore we have to increase the memory limit 2-3 times to download it once. \\nLater on, the service doesn\'t consume as much memory, so it\'s a start up cost.\\n\\n\\n### The challenge: cut down the memory consumption as much as we can.\\n\\nLet\'s get back to the basic of network communication.\\n\\n:::note\\nWe skip TLS termination for the sake of simplicity.\\n:::\\n\\nThere is a great book that explains it very well: https://hpbn.co/building-blocks-of-tcp/#slow-start\\n\\n![img](./syn.svg)\\n\\nJust a litle picture to remind us how a connection starts: we do a handshake with the service.\\n\\nThen we can start exchanging data.\\nTypical API responses are at most ~50kb.\\n\\nBut what if you want to warm a cache? How much can it be? \\nIt can be a lot, around tens of megabytes.\\nIn my example, we take 250mb.\\n\\nHow does the server send such data?\\n\\n![img](./congestion.svg)\\n\\nSlowly, packet by packet.\\n\\nThe server tries to understand your throughput. The protocol itself rarely provides an accurate value of a packet size, so by relying on the imperical latency, it tunes the packet size little by little.\\nIt needs to send a lot of packets to transfer a really big response.\\n\\n### 3 Ways to do it\\n\\nBelow we will consider 3 approaches to solve this task.\\nThere is no such thing as the only right solution; all of them are fine as long as you understand the costs and risks well enough, and we are gonna cover them.\\n\\n### First, Brute Force solution.\\n\\n:::warning\\nIf you want to reproduce an example make sure to untar server/json.tar.gz; it must contain the f.json file since GitHub has a limit of up to 100mb for a file.\\n:::\\n\\nYou can imagine how the simplest Go HTTP client can implement it or just look at the code.\\n\\n[Link](https://github.com/dennypenta/http-response-lab/blob/543510947c0b19dbc0097adf403ae5cd6954c1cc/client/main.go)\\n\\nThe implementation is straight forward: it sends a request, gets a response, reads, marhsals it into a defined structure, holds it in the memory and ready to serve it further.\\n\\nAnd here is the pprof output:\\n\\n```shell\\nShowing nodes accounting for 229.48MB, 100% of 229.48MB total\\n flat flat% sum% cum cum%\\n 229.48MB 100% 100% 229.48MB 100% io.ReadAll\\n 0 0% 100% 229.48MB 100% main.main\\n 0 0% 100% 229.48MB 100% runtime.main\\n```\\n\\nYes, it\'s not real win, with huge memory consumption, but it works ok.\\n\\nWe see all the memory consumed on reading the HTTP stream.\\n\\nOr you might say, \\"What a noob, you must use `json.Decoder`\\" so as to let the decoder work with the HTTP pipe closer.\\n\\nAnd it\'s pretty much the same, in my example, even worse.\\n[Link](https://github.com/dennypenta/http-response-lab/blob/b6ee7fcfd69fdffad844eb6a3d324d2fe3040985/client/main.go) to code with Decoder\\n\\n```shell\\nShowing nodes accounting for 384MB, 100% of 384MB total\\n flat flat% sum% cum cum%\\n 384MB 100% 100% 384MB 100% encoding/json.(*Decoder).refill\\n 0 0% 100% 384MB 100% encoding/json.(*Decoder).Decode\\n 0 0% 100% 384MB 100% encoding/json.(*Decoder).readValue\\n 0 0% 100% 384MB 100% main.main\\n 0 0% 100% 384MB 100% runtime.main\\n```\\n\\nTo recall why let\'s dig a little into the json/encoding library [implementation](https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/encoding/json/stream.go;l=49). \\n\\n```go\\nfunc (dec *Decoder) Decode(v any) error {\\n\\tif dec.err != nil {\\n\\t\\treturn dec.err\\n\\t}\\n\\n\\tif err := dec.tokenPrepareForDecode(); err != nil {\\n\\t\\treturn err\\n\\t}\\n\\n\\tif !dec.tokenValueAllowed() {\\n\\t\\treturn &SyntaxError{msg: \\"not at beginning of value\\", Offset: dec.InputOffset()}\\n\\t}\\n\\n\\t// Read whole value into buffer.\\n\\tn, err := dec.readValue()\\n\\tif err != nil {\\n\\t\\treturn err\\n\\t}\\n\\tdec.d.init(dec.buf[dec.scanp : dec.scanp+n])\\n\\tdec.scanp += n\\n\\n\\t// Don\'t save err from unmarshal into dec.err:\\n\\t// the connection is still usable since we read a complete JSON\\n\\t// object from it before the error happened.\\n\\terr = dec.d.unmarshal(v)\\n\\n\\t// fixup token streaming state\\n\\tdec.tokenValueEnd()\\n\\n\\treturn err\\n}\\n```\\n\\nIt does exactly the same, it calls `dec.readValue()` first to read all the response and then `dec.d.unmarshal` to parse it.\\n\\nAnd it\'s ok; the reason is very simple: **encoding/json doesn\'t know the nature of your data.**\\n\\n:::note\\nLibraries like [json-iter](https://github.com/json-iterator/go) or [easyjson](https://github.com/mailru/easyjson) offer zero improvements in memory consumption.\\n:::\\n\\n### Second, decode object by object.\\n\\nGo json library provides a method of the Decoder called [`Token`](https://pkg.go.dev/encoding/json#Decoder.Token)\\n\\nThis approach, parsing manually token by token, can give us an option to manually parse the json.\\nA token might be every symbol, such as as open bracket, quote, key, value, etc.\\nBut I found this approach quite complex. Having a deeply nested JSON object makes it very confusing to understand the relation for a given token. An solution could be to hold every key and designated level, but the decision gets worse with duplicated keys on a couple of levels.\\n\\nThat\'s why I prefer another approach.\\n\\nThere is a well-known problem on LeetCode called \\"[Valid Parentheses](https://leetcode.com/problems/valid-parentheses/description/)\\"\\n\\nWe can simply read the beginning of a given object and the end, understanding when the last bracket of the object comes.\\n\\n[Link](https://github.com/dennypenta/http-response-lab/blob/b5890cbb74282416b5adacc92de95f18f7ee766f/client/main.go#L110)\\n\\npprof gives the following output\\n```shell\\n(pprof) top 5\\nShowing nodes accounting for 68.56MB, 100% of 68.56MB total\\nShowing top 5 nodes out of 10\\n flat flat% sum% cum cum%\\n 27.55MB 40.18% 40.18% 68.56MB 100% main.decode\\n 20MB 29.17% 69.35% 20MB 29.17% encoding/json.(*decodeState).literalStore\\n 20MB 29.17% 98.52% 20MB 29.17% bufio.NewReaderSize (inline)\\n 1.01MB 1.48% 100% 1.01MB 1.48% bufio.(*Scanner).Text (inline)\\n 0 0% 100% 20MB 29.17% encoding/json.(*decodeState).object\\n```\\n\\nUsually, the output varies between 65-80mb. \\n\\nSuch adventages is achieved due to marshalling the json **and** reading the HTTP response at the same time.\\n\\nLet\'s get back to the introduction. Such a huge response gives us a stream of HTTP chunks we read step by step until the FIN message comes.\\nWe can\'t make the HTTP server split every object in the response for us (probably we can, but it brings even more complexity).\\nInstead, every given chunk window we can ask, \\"Does it contain a valid json object?\\"\\n\\nAs soon as a valid object has come, we can marshal it and continue reading the response further **until the next valid JSON object comes**.\\n\\n### Third, the simplest: data compression.\\n\\nIt was new to me to discover that the most efficient solution will nott be related to the response handling.\\n\\n**We simply must transfer as little data as we can.**\\n\\nJSON is not the only way to represent the data.\\nIt\'s easy and human-readable, but sometimes we have to trade it.\\n\\nThere are plenty of formats we can apply:\\n- Avro\\n- Tthrift\\n- MessagePack\\n- Gob (Go only)\\n- Protobuf\\n\\nAnd most likely more I don\'t even know.\\n\\nI tried replacing decoding to MessagePack and gave very litle result (zero \\\\_(\u30c4)_/).\\n\\nThe best outcome showed Protobuf.\\n:::note\\nWe still use HTTP/1.1; we don\'t use gRPC transport.\\n:::\\n\\nThe output from pprof is even better with less effort to implement.\\nIt may vary up to 50mb sometimes.\\n\\n```shell\\n(pprof) top5\\nShowing nodes accounting for 30.79MB, 100% of 30.79MB total\\n flat flat% sum% cum cum%\\n 30.79MB 100% 100% 30.79MB 100% io.ReadAll\\n 0 0% 100% 30.79MB 100% main.decode\\n 0 0% 100% 30.79MB 100% main.main\\n 0 0% 100% 30.79MB 100% runtime.main\\n```\\n\\nHere is the solution: [Link](https://github.com/dennypenta/http-response-lab/blob/main/client/main.go#L14)\\n\\nWhat we can say about Gob? \\n\\nIt offers very specific decoding and is a Go-only implementation, but it doesn\'t provide any benefit, here is the pprof output\\n```shell\\n(pprof) top5\\nShowing nodes accounting for 70.81MB, 100% of 70.81MB total\\nShowing top 5 nodes out of 20\\n flat flat% sum% cum cum%\\n 30.53MB 43.12% 43.12% 30.53MB 43.12% internal/saferio.ReadData\\n 28.28MB 39.94% 83.05% 28.28MB 39.94% reflect.growslice\\n 12MB 16.95% 100% 12MB 16.95% encoding/gob.decString\\n 0 0% 100% 70.81MB 100% encoding/gob.(*Decoder).Decode\\n 0 0% 100% 70.81MB 100% encoding/gob.(*Decoder).DecodeValue\\n```\\n\\nPerhaps for someone, having schemaless implementation is valuable, so here is the solution [link](https://github.com/dennypenta/http-response-lab/blob/main/client/main.go#L40)\\n\\n\\n### Conclusion\\n\\nI found 2 interesting ideas to me during the investigation.\\n1. The best, or one of them, solution might be the most obvious, so obvious to one is not to everyone.\\n2. It\'s not hard to implement and dig into fundamentals; some may win from engineering a new bicycle."},{"id":"why-a-blog","metadata":{"permalink":"/mynameis/blog/why-a-blog","source":"@site/blog/01-why-you-need-a-blog/index.mdx","title":"Why this page exists","description":"Blog is a\xa0 system to spread ideas across the internet. Shout out about a thing \\"Look, I have an opinion on that if you care\\".","date":"2023-12-13T21:25:34.000Z","formattedDate":"December 13, 2023","tags":[{"label":"career","permalink":"/mynameis/blog/tags/career"}],"readingTime":3.305,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"why-a-blog","title":"Why this page exists","authors":["denis"],"tags":["career"]},"unlisted":false,"prevItem":{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json"}},"content":"Blog is a\xa0 system to spread ideas across the internet. Shout out about a thing \\"Look, I have an opinion on that if you care\\".\\n\\n\x3c!--truncate--\x3e\\n\\nI have opinion on different things, especially in software. I\'ve been working on it since 2015. \\n\\nSo let\'s start from reasoning why you might want to own one.\\n\\n## It makes more than 0 chances somebody will find it and share your opinion\\n\\nOr disagree, it\'s also fine and in some cases means almost the the same for you.\\n\\nYou get audience.\xa0\\n\\nAnd it\'s a big deal.\\n\\nFirst, the audience challenges your ideas. It\'s good to find a person to discuss your ideas. It allows your either find weaknesses in the idea itself, or perhaps your mindset to find crucial vocabulary to express what it means for you, or become even more confident on a topic. After all, it\'s just a joy to discuss what you have on top of your head.\\n\\n## More than 0 chances your future team knows you\\n\\nIt\'s a well known that having a referral in a company makes hiring easier to everyone. They get plus a point in confidence they hire not a dumbass, you may skip long questionnaire. They refer you not because you are good at contribution, but it\'s easier to build ubiquitous language in the team when you know each other.\\n\\nI want to say having written something valuable for others makes you a little more known that you used to be. And if you apply to a new job and they have found it - it bumps your chances a lot.\\n\\nIm convinced in the idea that not just delivering good result to your company, but telling the best pieces to the others will pay me off later on.\\n\\nThe only thing is under question if we really have built and understood something important for the industry.\\n\\n## Memo is good\\n\\nDuring software experience I realised the wide range technologies I apply can hardly be stored in my head.\\n\\nTools such Obsidian are fancy, but Im not disciplined enough to handle my cloud to store it or just structure them well enough, it doesn\'t fit me.\\n\\nSo Im going to structure my experience here.\\n\\nIt\'s not just putting all I have in my memory, but also try structuring all new stuff I have in my head.\\n\\nFor instance, I want to memoize a way to define alerts using terraform. Even though I\'ve done it I have no idea what those queries to an observability provider mean.\xa0\\n\\nWhat should I do?\\n\\nNot to fool people. I will figure out in order to explain it to the others. Otherwise the article will be one of the thousands on medium or linkedin.\\n\\nEventually I have to push my skill up to give my audience valuable experience shared.\\n\\nIn the same time I get structured my experience and making it better by reading more in order to write a little.\\n\\n## Expressing better\\n\\nAnd my personal reason. \\n\\nIm poor at structuring my speach. If you read it you know how hard it was to catch my ideas. But I fight against it and I believe the blog may make me write more often and amend the way I express myself.\\n\\n## You are ready. what now?\\n\\nOk, let\'s say you confirmed you have a reason to have a blog.\\n\\n \\n\\nA couple of hints I want to add.\\n\\n \\n\\nPlatforms like medium blocks people from reading your content without subscription. \\nAnd definitely it\'s not what I want.\\n\\nI can understand if you want to setup patreon to provide sub only data, but I don\'t consider such option.\xa0\\nMoreover, the platforms get bigger revenue chunk of your ad and don\'t do more than google does.\\n\\nI picked docusaurus because I have full control on codebase, fonts, styles, ads, comments, structuring. And I was lucky enough to find a template I wanted to reuse by [takken](https://takken.io/).\\n\\nOr you can just clone this [project](https://github.com/dennypenta/mynameis)."}]}')}}]); \ No newline at end of file diff --git a/assets/js/2f6ea139.b01cd6c9.js b/assets/js/2f6ea139.b01cd6c9.js new file mode 100644 index 0000000..40a6687 --- /dev/null +++ b/assets/js/2f6ea139.b01cd6c9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[538],{6362:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"tq-devlog-1","metadata":{"permalink":"/mynameis/blog/tq-devlog-1","source":"@site/blog/05-tq-devlog-1/index.md","title":"PaaS devlog |#1","description":"Devlog |#1","date":"2024-09-03T18:48:09.000Z","formattedDate":"September 3, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":3.295,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"tq-devlog-1","title":"PaaS devlog |#1","authors":["denis"],"tags":["software"]},"unlisted":false,"nextItem":{"title":"PaaS devlog |#0","permalink":"/mynameis/blog/tq-devlog-0"}},"content":"## Devlog |#1\\n\\nAnother day I actually started working on the project (what a surprise).\\n\\nI want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.\\n\\n\x3c!--truncate--\x3e\\n\\nIm convinced I will store my data in postgres, therefore I need a local instance, migrations, a tool to lookup the data.\\n\\nFirst, docker compose. I can\'t imagine local environment without it. Very simple one, some volumes, passwordless acceess, expose 5432 port, done.\\n\\nI didn\'t know how my first feature will look like, a user creating, connecting a repository or saving the infrastracture state.\\nBut I needed a first migration to test it, so I created a users table. Very creative, but I really will need users table, it\'s fine.\\n\\nI installed a few dependencies:\\n```shell\\ngo get github.com/golang-migrate/migrate/v4\\ngo get github.com/jmoiron/sqlx\\ngo get github.com/jackc/pgx\\n```\\n\\nI will sqlx + squirrel for query executing, pgx as a driver and migrate for running migrations, it prodes cli interface if you want to run in the jobs and go api as well.\\n\\nI will use go api, but I wouldn\'t recomment it in production, it\'s important to create a database backup before starting a mgiration, so the best case you have a migration job that makes a backup and then runs the migration, if it worked out - release is welcome.\\n\\nThen I made a few commands to work with migration like create new, up, down and fix migration.\\n\\n:::note\\nMigration package stores the state in the same database. When it fails it writes the migration as `dirty`. Fix command is used to force the version, it\'s very useful in the development process. I even used it in prod. \\n:::\\n\\n```makefile\\nDB_DSN ?= \\"postgres://postgres@localhost:5432/tq?sslmode=disable\\"\\n\\nmigrate_new:\\n migrate create -ext sql -dir migrations -seq -digits 4 ${MNAME}\\n\\nmigrate_up:\\n migrate -path migrations -database ${DB_DSN} up\\n\\nmigrate_down:\\n migrate -path migrations -database ${DB_DSN} down\\n\\nmigrate_fix:\\n migrate -path migrations -database ${DB_DSN} force ${V}\\n\\nmigrate_v:\\n migrate -path migrations -database ${DB_DSN} version\\n```\\n\\nUsing command `make migrate_new users_table` I create a new migration and feel it with the following sql:\\n```sql\\nCREATE EXTENSION IF NOT EXISTS \\"uuid-ossp\\";\\n\\nCREATE TABLE IF NOT EXISTS users (\\n id uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,\\n email varchar(85) NOT NULL,\\n password varchar(255) NOT NULL,\\n\\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL\\n);\\n```\\n\\nI like using uuid as an identity. It never fooled me. \\n\\nThen I do what I didn\'t recommend.\\n\\nYes, I run the migrations right in the starting the app server.\\nSeems ok, applied.\\n\\nI need something to see the result, the table, the extension.\\nI use psql, but to me personnaly it\'s very annoying having such long interface, it matters a lot when I have a few databases to follow.\\n\\nI looked for a tool again. I tried pgadmin, jetbrains embedded one. \\nAnd I found Beekeeper. That\'s the tool I wouldn\'t be ashamed to create. Looks very good, easy to use, to edit, look for data with 0 sql, comfortable keyboard control. \\nEverything I like. \\n__It\'s even opensourced and has a free community edition.__\\n\\nI looked at the data, the migration record exists, the users table does as well. \\n\\n![img](./beekeeper.png)\\n\\nFinally I can commit it.\\nI like using lazygit for most of my cases.\\nIt also a keyboard only control.\\nEven my brain can handle it, there are very few commands: arrows to navigate, space to stage a change, you can use mouse to stage only a part of the file, and push `c` to input a commit message and `Enter` to commit. \\nIt also has bunch of things like branches list, reflog, command log. \\n\\nAt least I don\'t repeatadly do anymore `ls, gd, ga` file by file.\\n\\n:::note\\nI use zsh and it gives me many shortcuts, for instance `ga` is equal to `git add`\\n:::\\n\\n![img](./git.png)\\n\\nThank you for reading, come here and see what\'s gonna be in the end.\\nRepository is here: http://github.com/treenq/treenq"},{"id":"tq-devlog-0","metadata":{"permalink":"/mynameis/blog/tq-devlog-0","source":"@site/blog/04-tq-devlog-0/index.md","title":"PaaS devlog |#0","description":"Devlog |#0","date":"2024-09-02T20:12:28.000Z","formattedDate":"September 2, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":3.955,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"tq-devlog-0","title":"PaaS devlog |#0","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"PaaS devlog |#1","permalink":"/mynameis/blog/tq-devlog-1"},"nextItem":{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev"}},"content":"## Devlog |#0\\n\\nToday I want to share with you my first steps of creating new project.\\nFor a long time I\'ve wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service.\\n\\n\x3c!--truncate--\x3e\\n\\nThe main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration.\\n\\n:::tip\\nYou can read more about cdk [here](https://developer.hashicorp.com/terraform/cdktf)\\n:::\\n\\nAll the infra will be used from a well known cloud providers (not aws ofc, no clue who can understand how to user it).\\nFirst iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me.\\n\\n### The problem\\n\\nThe technical problem exists, it\'s fun to figure out.\\nBut no the main one. The biggest fight Im gonna accept is __procrastination__. Im such a person who pushes further all the tasks very often. I just have little to do with time discipline. That\'s what will stop me from the progress.\\nSo the easiest way to move progress away - do whatever, but not the progress.\\n\\n### The planing\\n\\nSo I decided to plan everything and understand how big the actual project is gonna be.\\nSo I start speaking with GPT in order to express my mind, kinda talking to a duck. \\nInstead of asking what I should do I explained my plan and asked to ask __more questions__ so it could help me to clarify the technical solution and the plan.\\n\\n![img](./gpt.png)\\n\\n
\\n\\nHere you can find a prompt I used\\n\\nI want to develop a platform like digitalocean app, vercel, render, fly.io, heroku, etc. My value is the following: I give observability with 0 code changes, and a localdev opportunity with connecting to a cloud environment, for instance a request comes from a frontend app on staging to my backend app locally so I could intercept it and make my laptop appear kinda in the cloud. It\'s a multitenant project. There are 2 paths: kubernetes and a custom architecture. To build a custom architecture the app must be on a few virtual machines, a load balancer on top including firewall. The challenge: ask me necessary questions so we could make a right decision. I have to highlight, we build a users\' environment, not the product architecture I will create in order to reproduce the given environment, so we need to decide that would fit me and users better.\\n
\\n\\nInitially I thought I will do it providing a user set of virtual machines connected under VPC, putting a load balancer on top, back to 2000. I thought it will make it cheaper and some tools just easier to implement.\\n\\nChatting to GPT I realized - Kubernetes will provide it a way quicker, most of the stuff is just ready to go like network policies, load balancing, SSL, deployment/rollback, health monitoring, resources observability, Istio adoption. Istio is very useful for observability and local first development, it became a new word today - __remocal__.\\n\\nWhen stepped into the planning I decided to make it even longer.\\nI wanted to researched all the kanban boards, unresistable.\\nI used to use Trello and it was ok, but using api in power-ups boundaries sucks. Not really somethign I need right now though. \\n\\nI tried Cluckup, it\'s a laggish joke, even worse than Jira to make you feel you are already enterprise.\\nI tried Asana and saw 0 difference with Trello, I spent about 2 minutes to confirm it and exist.\\n\\n### The ugly thing\\n\\nIn the end I found Linear. \\nTo be fair it looked ugly, the design is equal to supabase: fonts, buttons.\\n\\nA few minutes later I started catching.\\nKeyboard first design - that\'s what I buy.\\n\\nSo I read Linear Method, the framework they apply internally. It was hard to accept it, I think older I get more conservatibe I become, but I dig it anyway.\\nThe basic element is an issue. It might have sub-issues. And they might have.\\nThey can be collected in a project.\\n\\nThere are bunch of other staff I don\'t use, but I will share it below.\\n- Cycle - like a sprint, hate it.\\n- Triage - inbox, it\'s a boss feature in my opinion, you can aggregate communication channels in a single place, then an on-call person can carry them, create issues or remove.\\n- Initiative - collection of the projects, they can be presented as a time line or a strategy decision, or even a roadmap on a timeline. \\n\\nAs a result I cooked quite a few cards (48 projects in a backlog \ud83d\ude31\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f).\\n\\n![img](./few.png)\\n\\nThank you for reading, come here and see what\'s gonna be in the end.\\nRepository is here: http://github.com/treenq/treenq"},{"id":"do-gamedev","metadata":{"permalink":"/mynameis/blog/do-gamedev","source":"@site/blog/03-do-gamedev/index.mdx","title":"Backend Guy Ventures into Game Development","description":"In order to be engaged one explores different areas and looks for unknown software area.","date":"2024-09-02T18:32:54.000Z","formattedDate":"September 2, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":6.53,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"do-gamedev","title":"Backend Guy Ventures into Game Development","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"PaaS devlog |#0","permalink":"/mynameis/blog/tq-devlog-0"},"nextItem":{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json"}},"content":"In order to be engaged one explores different areas and looks for unknown software area.\\n\\nHere we look at the gamedev in 2024 from experience in server side software.\\n\\nIn software development, it\'s common to explore new domains to stay engaged. \\nWhether it\'s for a change of pace or to push personal boundaries, exploring the unknown can lead to fancy adventures in software. \\nThis page will share my journey as a backend developer diving into the game development in 2024.\\n\\n\x3c!--truncate--\x3e\\n\\n#### Why Gamedev? \\n\\n99% of programmes came here to make a game.\\nEither did I.\\n\\nFrom a young age, I was captivated by two genres: strategy games and action RPGs. \\nMy first PC came preloaded with classics like Red Alert 2, Heroes of Might and Magic 3, and Diablo 2. \\nThe simple yet addictive gameplay\u2014click, move, destroy, enjoy \u2014 cemented my love for these genres. \\nOver the years, I\u2019ve played many iconic RTS games like Warcraft 3 and Starcraft 2 (and still do occasionally).\\nBut I realized that Starcraft 2 and similar games leaned more towards real-time execution rather than strategic depth.\\n\\nSo I decided to make my own game with the strategy and decision making take the center stage.\\n\\n#### Choosing the Game Engine \\n\\nThere are numerous options out there\u2014Defold, RPG Maker, GameMaker, Construct, to name a few.\\n\\nBut I focused on the big three that are free to start with, offer extensive flexibility, and have been tested by major projects: Unreal Engine, Unity, and Godot.\\n\\n#### Unreal Engine: A Mixed Bag of Power and Complexity\\n\\nI chose to start with Unreal Engine. It has a large community, though not the largest. Everything Unity offers in its asset store, Unreal has an equivalent. The engine supports C++ for low-level programming and Blueprints (a visual scripting language) for level design, though you can use either approach.\\n\\nInstalling the engine is a hassle. You need to first install the Epic Games Launcher and then download the 55GB engine itself, which can be a chore if your disk space is limited.\\n\\nAfter setting up a blank project, I was impressed by the vast flexibility Unreal offers. You get all the benefits of C++\u2014dynamic dependency injection, custom components, and more.. But it adds complexity.\\n1. Compiliation time. It exists. Not just exists like a couple blinks 5-10 seconds, it takes a lot of time to build a single class to start using it in the project.\\n2. Code complexity. Write header files, manual memory management. Good package manager doesn\'t exist in 2024, now I understand why they love Rust so much. \\n3. Poor mac support. No comments, even the interface of top bar menu is different, I was struggling to find editor settings according to the documentation, and every question is like that. \\n\\nI would recommend such engine for people who likes waiting, c++ and want to make a beatiful scenes with nice action. \\nI also have to note that engine is open source and owned by a technical guy and people who actually make games. I would stop there if I liked waiting and c++.\\n\\n#### Unity: The Industry Standard.\\n\\nNext up was Unity, the most popular game engine out there. \\nUnity has a vast ecosystem, with advanced features like rendering, post-processing, and easy shader creation. \\nIt\u2019s backed by a huge asset store, which should theoretically make development easier.\\nC# - Im not a big fun, but it\'s compilable, therefore type safe, seems good.\\n\\nA basic abstraction is an object. An object has compenents to manage what is it, it might be a script to move it, a mesh to render a tree, a colission not to pass through the tree, sound to play as tree leafs on the wind and so on.\\nSeems quite simple. \\n\\nBut when I approached a real problem there are plenty of weird things.\\n1. Unity has three different render pipelines, which aren\u2019t compatible with each other. The oldest one is being deprecated, meaning half the assets in the store may soon be obsolete.\\n2. Asset store is a garbage. I tried several camera controllers, and only one partially met my needs. I had to patch it to double its functionality, which felt like reinventing the wheel.\\n\\nWe all remember the Unity pricing drama. It has a closed-source codebase, and now there\u2019s a tracker that counts installations to generate more revenue for shareholders. \\nThis has led to a lot of half-baked features and outdated documentation, which can make the engine feel unstable.\\n\\nUnity is still a solid choice, but in 2024, it feels like the engine is in a weird transitional state. \\nThe documentation isn\u2019t as up-to-date as it should be, and the engine itself seems to be in a half-finished state. \\nI might revisit it in 2025 when Unity 6 is released.\\n\\n#### Godot: Unknown creature in the Sea.\\n\\nFinally, I turned to Godot, an engine I initially underestimated. \\nKnown for its strong 2D capabilities, Godot seemed lacking in 3D support. \\nIts physics engine was also rumored to be subpar.\\n\\nSo I start doing a 3D. \\nFirst I found that asset library is poor, camera controller only for Godot 3 (previous release) and it makes no sense to use Godot 3 in 2024.\\n\\nWhat I actually see in progress.\\n0. Godot\u2019s installation bundle is just 150MB. It has a negligible memory footprint and can run smoothly even on modest hardware. Coming from Unity, this was a breath of fresh air.\\n1. Godot\u2019s editor can be extended in a similar manner to Unity, allowing you to add new UI elements and dynamically instantiate new components.\\n2. The asset library isn\u2019t a store but a repository where everything is distributed for free. Since Godot is open-source, I doubt any significant part of it will go paid, unlike Unity and Unreal, where quality assets often come with a price tag.\\n3. Physics engine implementation can be replaced with jolt easy-peasy and works very well.\\n4. The same abstractions, the same component building, but not an object has component, rather a scene (actually a node) has nodes (the others to implement actual behavior of the node).\\n5. Exporting is just a button click. I managed to build a project for windows in Mac, it\'s so good, haven\'t had such smooth exprerience.\\n\\nIt was surprisingly easy to understand the basics, the nodes design, the event bus system, for a backend guy it\'s perfect to start making a real game.\\n\\nGDScript can fail in runtime, not the best, but you can use C# for the sake of compilte time failure.\\n\\nAnd I know, the community is smaller, it will be developed slower, true. But I care about me today, not the community.\\n\\nI initially planned to give Unity a fair shot, spending a week with both engines. \\nBut after just two days with Godot, I was progressing so much faster that I decided it wasn\u2019t worth the time to continue with Unity. \\nGodot\u2019s lower entry barrier and faster development pace made it the clear choice for me.\\n\\n##### I want to finish simpler. \\n\\nIn the end, the best engine is the one that aligns with your needs and preferences. \\nRemember, Blender was once considered a niche tool while everyone used 3D Max, and now Blender is the industry standard. \\nFirebase was just a \u201cbase,\u201d and today we have Supabase, Pocketbase and many others.\\n\\nThe landscape of game development is always changing. \\nWhat matters most is finding the tool that helps you bring your vision to life, not what the industry standard is. \\nFor me, that tool is Godot.\\n\\n### Lessons\\nSpoiler, no, I didn\'t finish a game, I learned the gamedev abstractions and played with the engines a bit and I enjoyed it.\\nAnd it\'s fine, I had good time and wish everyone to find a toy you can spend some time on and make you engaged."},{"id":"big-json","metadata":{"permalink":"/mynameis/blog/big-json","source":"@site/blog/02-250mbjson-in-50mb-limit/index.mdx","title":"250mb json in a 40mb service limit","description":"This article has been created to remind us of one simple thing: HTTP is a stream.","date":"2024-05-26T15:48:12.000Z","formattedDate":"May 26, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":6.8,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"big-json","title":"250mb json in a 40mb service limit","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev"},"nextItem":{"title":"Why this page exists","permalink":"/mynameis/blog/why-a-blog"}},"content":"This article has been created to remind us of one simple thing: HTTP is a stream.\\n\\nAs a practical outcome we can learn how to reduce memory requirements for our services in a typical task: cache warming.\\n\\n\x3c!--truncate--\x3e\\n\\nLet\'s look at the challenge first.\\n\\nWe have a service that must download the data and keep it in memory.\\nThe issue is the JSON document we have to download is 10 times larger than the encoded data. \\nTherefore we have to increase the memory limit 2-3 times to download it once. \\nLater on, the service doesn\'t consume as much memory, so it\'s a start up cost.\\n\\n\\n### The challenge: cut down the memory consumption as much as we can.\\n\\nLet\'s get back to the basic of network communication.\\n\\n:::note\\nWe skip TLS termination for the sake of simplicity.\\n:::\\n\\nThere is a great book that explains it very well: https://hpbn.co/building-blocks-of-tcp/#slow-start\\n\\n![img](./syn.svg)\\n\\nJust a litle picture to remind us how a connection starts: we do a handshake with the service.\\n\\nThen we can start exchanging data.\\nTypical API responses are at most ~50kb.\\n\\nBut what if you want to warm a cache? How much can it be? \\nIt can be a lot, around tens of megabytes.\\nIn my example, we take 250mb.\\n\\nHow does the server send such data?\\n\\n![img](./congestion.svg)\\n\\nSlowly, packet by packet.\\n\\nThe server tries to understand your throughput. The protocol itself rarely provides an accurate value of a packet size, so by relying on the imperical latency, it tunes the packet size little by little.\\nIt needs to send a lot of packets to transfer a really big response.\\n\\n### 3 Ways to do it\\n\\nBelow we will consider 3 approaches to solve this task.\\nThere is no such thing as the only right solution; all of them are fine as long as you understand the costs and risks well enough, and we are gonna cover them.\\n\\n### First, Brute Force solution.\\n\\n:::warning\\nIf you want to reproduce an example make sure to untar server/json.tar.gz; it must contain the f.json file since GitHub has a limit of up to 100mb for a file.\\n:::\\n\\nYou can imagine how the simplest Go HTTP client can implement it or just look at the code.\\n\\n[Link](https://github.com/dennypenta/http-response-lab/blob/543510947c0b19dbc0097adf403ae5cd6954c1cc/client/main.go)\\n\\nThe implementation is straight forward: it sends a request, gets a response, reads, marhsals it into a defined structure, holds it in the memory and ready to serve it further.\\n\\nAnd here is the pprof output:\\n\\n```shell\\nShowing nodes accounting for 229.48MB, 100% of 229.48MB total\\n flat flat% sum% cum cum%\\n 229.48MB 100% 100% 229.48MB 100% io.ReadAll\\n 0 0% 100% 229.48MB 100% main.main\\n 0 0% 100% 229.48MB 100% runtime.main\\n```\\n\\nYes, it\'s not real win, with huge memory consumption, but it works ok.\\n\\nWe see all the memory consumed on reading the HTTP stream.\\n\\nOr you might say, \\"What a noob, you must use `json.Decoder`\\" so as to let the decoder work with the HTTP pipe closer.\\n\\nAnd it\'s pretty much the same, in my example, even worse.\\n[Link](https://github.com/dennypenta/http-response-lab/blob/b6ee7fcfd69fdffad844eb6a3d324d2fe3040985/client/main.go) to code with Decoder\\n\\n```shell\\nShowing nodes accounting for 384MB, 100% of 384MB total\\n flat flat% sum% cum cum%\\n 384MB 100% 100% 384MB 100% encoding/json.(*Decoder).refill\\n 0 0% 100% 384MB 100% encoding/json.(*Decoder).Decode\\n 0 0% 100% 384MB 100% encoding/json.(*Decoder).readValue\\n 0 0% 100% 384MB 100% main.main\\n 0 0% 100% 384MB 100% runtime.main\\n```\\n\\nTo recall why let\'s dig a little into the json/encoding library [implementation](https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/encoding/json/stream.go;l=49). \\n\\n```go\\nfunc (dec *Decoder) Decode(v any) error {\\n\\tif dec.err != nil {\\n\\t\\treturn dec.err\\n\\t}\\n\\n\\tif err := dec.tokenPrepareForDecode(); err != nil {\\n\\t\\treturn err\\n\\t}\\n\\n\\tif !dec.tokenValueAllowed() {\\n\\t\\treturn &SyntaxError{msg: \\"not at beginning of value\\", Offset: dec.InputOffset()}\\n\\t}\\n\\n\\t// Read whole value into buffer.\\n\\tn, err := dec.readValue()\\n\\tif err != nil {\\n\\t\\treturn err\\n\\t}\\n\\tdec.d.init(dec.buf[dec.scanp : dec.scanp+n])\\n\\tdec.scanp += n\\n\\n\\t// Don\'t save err from unmarshal into dec.err:\\n\\t// the connection is still usable since we read a complete JSON\\n\\t// object from it before the error happened.\\n\\terr = dec.d.unmarshal(v)\\n\\n\\t// fixup token streaming state\\n\\tdec.tokenValueEnd()\\n\\n\\treturn err\\n}\\n```\\n\\nIt does exactly the same, it calls `dec.readValue()` first to read all the response and then `dec.d.unmarshal` to parse it.\\n\\nAnd it\'s ok; the reason is very simple: **encoding/json doesn\'t know the nature of your data.**\\n\\n:::note\\nLibraries like [json-iter](https://github.com/json-iterator/go) or [easyjson](https://github.com/mailru/easyjson) offer zero improvements in memory consumption.\\n:::\\n\\n### Second, decode object by object.\\n\\nGo json library provides a method of the Decoder called [`Token`](https://pkg.go.dev/encoding/json#Decoder.Token)\\n\\nThis approach, parsing manually token by token, can give us an option to manually parse the json.\\nA token might be every symbol, such as as open bracket, quote, key, value, etc.\\nBut I found this approach quite complex. Having a deeply nested JSON object makes it very confusing to understand the relation for a given token. An solution could be to hold every key and designated level, but the decision gets worse with duplicated keys on a couple of levels.\\n\\nThat\'s why I prefer another approach.\\n\\nThere is a well-known problem on LeetCode called \\"[Valid Parentheses](https://leetcode.com/problems/valid-parentheses/description/)\\"\\n\\nWe can simply read the beginning of a given object and the end, understanding when the last bracket of the object comes.\\n\\n[Link](https://github.com/dennypenta/http-response-lab/blob/b5890cbb74282416b5adacc92de95f18f7ee766f/client/main.go#L110)\\n\\npprof gives the following output\\n```shell\\n(pprof) top 5\\nShowing nodes accounting for 68.56MB, 100% of 68.56MB total\\nShowing top 5 nodes out of 10\\n flat flat% sum% cum cum%\\n 27.55MB 40.18% 40.18% 68.56MB 100% main.decode\\n 20MB 29.17% 69.35% 20MB 29.17% encoding/json.(*decodeState).literalStore\\n 20MB 29.17% 98.52% 20MB 29.17% bufio.NewReaderSize (inline)\\n 1.01MB 1.48% 100% 1.01MB 1.48% bufio.(*Scanner).Text (inline)\\n 0 0% 100% 20MB 29.17% encoding/json.(*decodeState).object\\n```\\n\\nUsually, the output varies between 65-80mb. \\n\\nSuch adventages is achieved due to marshalling the json **and** reading the HTTP response at the same time.\\n\\nLet\'s get back to the introduction. Such a huge response gives us a stream of HTTP chunks we read step by step until the FIN message comes.\\nWe can\'t make the HTTP server split every object in the response for us (probably we can, but it brings even more complexity).\\nInstead, every given chunk window we can ask, \\"Does it contain a valid json object?\\"\\n\\nAs soon as a valid object has come, we can marshal it and continue reading the response further **until the next valid JSON object comes**.\\n\\n### Third, the simplest: data compression.\\n\\nIt was new to me to discover that the most efficient solution will nott be related to the response handling.\\n\\n**We simply must transfer as little data as we can.**\\n\\nJSON is not the only way to represent the data.\\nIt\'s easy and human-readable, but sometimes we have to trade it.\\n\\nThere are plenty of formats we can apply:\\n- Avro\\n- Tthrift\\n- MessagePack\\n- Gob (Go only)\\n- Protobuf\\n\\nAnd most likely more I don\'t even know.\\n\\nI tried replacing decoding to MessagePack and gave very litle result (zero \\\\_(\u30c4)_/).\\n\\nThe best outcome showed Protobuf.\\n:::note\\nWe still use HTTP/1.1; we don\'t use gRPC transport.\\n:::\\n\\nThe output from pprof is even better with less effort to implement.\\nIt may vary up to 50mb sometimes.\\n\\n```shell\\n(pprof) top5\\nShowing nodes accounting for 30.79MB, 100% of 30.79MB total\\n flat flat% sum% cum cum%\\n 30.79MB 100% 100% 30.79MB 100% io.ReadAll\\n 0 0% 100% 30.79MB 100% main.decode\\n 0 0% 100% 30.79MB 100% main.main\\n 0 0% 100% 30.79MB 100% runtime.main\\n```\\n\\nHere is the solution: [Link](https://github.com/dennypenta/http-response-lab/blob/main/client/main.go#L14)\\n\\nWhat we can say about Gob? \\n\\nIt offers very specific decoding and is a Go-only implementation, but it doesn\'t provide any benefit, here is the pprof output\\n```shell\\n(pprof) top5\\nShowing nodes accounting for 70.81MB, 100% of 70.81MB total\\nShowing top 5 nodes out of 20\\n flat flat% sum% cum cum%\\n 30.53MB 43.12% 43.12% 30.53MB 43.12% internal/saferio.ReadData\\n 28.28MB 39.94% 83.05% 28.28MB 39.94% reflect.growslice\\n 12MB 16.95% 100% 12MB 16.95% encoding/gob.decString\\n 0 0% 100% 70.81MB 100% encoding/gob.(*Decoder).Decode\\n 0 0% 100% 70.81MB 100% encoding/gob.(*Decoder).DecodeValue\\n```\\n\\nPerhaps for someone, having schemaless implementation is valuable, so here is the solution [link](https://github.com/dennypenta/http-response-lab/blob/main/client/main.go#L40)\\n\\n\\n### Conclusion\\n\\nI found 2 interesting ideas to me during the investigation.\\n1. The best, or one of them, solution might be the most obvious, so obvious to one is not to everyone.\\n2. It\'s not hard to implement and dig into fundamentals; some may win from engineering a new bicycle."},{"id":"why-a-blog","metadata":{"permalink":"/mynameis/blog/why-a-blog","source":"@site/blog/01-why-you-need-a-blog/index.mdx","title":"Why this page exists","description":"Blog is a\xa0 system to spread ideas across the internet. Shout out about a thing \\"Look, I have an opinion on that if you care\\".","date":"2023-12-13T21:25:34.000Z","formattedDate":"December 13, 2023","tags":[{"label":"career","permalink":"/mynameis/blog/tags/career"}],"readingTime":3.305,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"why-a-blog","title":"Why this page exists","authors":["denis"],"tags":["career"]},"unlisted":false,"prevItem":{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json"}},"content":"Blog is a\xa0 system to spread ideas across the internet. Shout out about a thing \\"Look, I have an opinion on that if you care\\".\\n\\n\x3c!--truncate--\x3e\\n\\nI have opinion on different things, especially in software. I\'ve been working on it since 2015. \\n\\nSo let\'s start from reasoning why you might want to own one.\\n\\n## It makes more than 0 chances somebody will find it and share your opinion\\n\\nOr disagree, it\'s also fine and in some cases means almost the the same for you.\\n\\nYou get audience.\xa0\\n\\nAnd it\'s a big deal.\\n\\nFirst, the audience challenges your ideas. It\'s good to find a person to discuss your ideas. It allows your either find weaknesses in the idea itself, or perhaps your mindset to find crucial vocabulary to express what it means for you, or become even more confident on a topic. After all, it\'s just a joy to discuss what you have on top of your head.\\n\\n## More than 0 chances your future team knows you\\n\\nIt\'s a well known that having a referral in a company makes hiring easier to everyone. They get plus a point in confidence they hire not a dumbass, you may skip long questionnaire. They refer you not because you are good at contribution, but it\'s easier to build ubiquitous language in the team when you know each other.\\n\\nI want to say having written something valuable for others makes you a little more known that you used to be. And if you apply to a new job and they have found it - it bumps your chances a lot.\\n\\nIm convinced in the idea that not just delivering good result to your company, but telling the best pieces to the others will pay me off later on.\\n\\nThe only thing is under question if we really have built and understood something important for the industry.\\n\\n## Memo is good\\n\\nDuring software experience I realised the wide range technologies I apply can hardly be stored in my head.\\n\\nTools such Obsidian are fancy, but Im not disciplined enough to handle my cloud to store it or just structure them well enough, it doesn\'t fit me.\\n\\nSo Im going to structure my experience here.\\n\\nIt\'s not just putting all I have in my memory, but also try structuring all new stuff I have in my head.\\n\\nFor instance, I want to memoize a way to define alerts using terraform. Even though I\'ve done it I have no idea what those queries to an observability provider mean.\xa0\\n\\nWhat should I do?\\n\\nNot to fool people. I will figure out in order to explain it to the others. Otherwise the article will be one of the thousands on medium or linkedin.\\n\\nEventually I have to push my skill up to give my audience valuable experience shared.\\n\\nIn the same time I get structured my experience and making it better by reading more in order to write a little.\\n\\n## Expressing better\\n\\nAnd my personal reason. \\n\\nIm poor at structuring my speach. If you read it you know how hard it was to catch my ideas. But I fight against it and I believe the blog may make me write more often and amend the way I express myself.\\n\\n## You are ready. what now?\\n\\nOk, let\'s say you confirmed you have a reason to have a blog.\\n\\n \\n\\nA couple of hints I want to add.\\n\\n \\n\\nPlatforms like medium blocks people from reading your content without subscription. \\nAnd definitely it\'s not what I want.\\n\\nI can understand if you want to setup patreon to provide sub only data, but I don\'t consider such option.\xa0\\nMoreover, the platforms get bigger revenue chunk of your ad and don\'t do more than google does.\\n\\nI picked docusaurus because I have full control on codebase, fonts, styles, ads, comments, structuring. And I was lucky enough to find a template I wanted to reuse by [takken](https://takken.io/).\\n\\nOr you can just clone this [project](https://github.com/dennypenta/mynameis)."}]}')}}]); \ No newline at end of file diff --git a/assets/js/5ea76644.05445aa6.js b/assets/js/5ea76644.05445aa6.js deleted file mode 100644 index f2d2289..0000000 --- a/assets/js/5ea76644.05445aa6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[644],{8826:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>d});var a=n(5893),i=n(1151);const o={slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},s=void 0,r={permalink:"/mynameis/blog/tq-devlog-0",source:"@site/blog/04-tq-devlog-0/index.md",title:"PaaS devlog |#0",description:"Devlog |#0",date:"2024-09-02T20:12:28.000Z",formattedDate:"September 2, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.91,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},unlisted:!1,nextItem:{title:"Backend Guy Ventures into Game Development",permalink:"/mynameis/blog/do-gamedev"}},l={authorsImageUrls:[void 0]},d=[{value:"Devlog |#0",id:"devlog-0",level:2},{value:"The problem",id:"the-problem",level:3},{value:"The planing",id:"the-planing",level:3},{value:"The ugly thing",id:"the-ugly-thing",level:3}];function c(e){const t={a:"a",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.a)(),...e.components},{Details:o}=t;return o||function(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"devlog-0",children:"Devlog |#0"}),"\n",(0,a.jsx)(t.p,{children:"Today I want to share with your my first steps of creating new project.\nFor a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service."}),"\n",(0,a.jsx)(t.p,{children:"The main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration.\nAll the infra will be used from a well known cloud providers (not aws ofc, no clue who can understand how to user it).\nFirst iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me."}),"\n",(0,a.jsx)(t.h3,{id:"the-problem",children:"The problem"}),"\n",(0,a.jsxs)(t.p,{children:["The technical problem exists, it's fun to figure out.\nBut no the main one. The biggest fight Im gonna accept is ",(0,a.jsx)(t.strong,{children:"procrastination"}),". Im such a person who pushes further all the tasks very often. I just have little to do with time discipline. That's what will stop me from the progress.\nSo the easiest way to move progress away - do whatever, but not the progress."]}),"\n",(0,a.jsx)(t.h3,{id:"the-planing",children:"The planing"}),"\n",(0,a.jsxs)(t.p,{children:["So I decided to plan everything and understand how big the actual project is gonna be.\nSo I start speaking with GPT in order to express my mind, kinda talking to a duck.\nInstead of asking what I should do I explained my plan and asked to ask ",(0,a.jsx)(t.strong,{children:"more questions"})," so it could help me to clarify the technical solution and the plan."]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(8323).Z+"",width:"817",height:"1036"})}),"\n",(0,a.jsxs)(o,{children:[(0,a.jsx)("summary",{children:(0,a.jsx)(t.p,{children:"Here you can find a prompt I used"})}),(0,a.jsx)(t.p,{children:"I want to develop a platform like digitalocean app, vercel, render, fly.io, heroku, etc. My value is the following: I give observability with 0 code changes, and a localdev opportunity with connecting to a cloud environment, for instance a request comes from a frontend app on staging to my backend app locally so I could intercept it and make my laptop appear kinda in the cloud. It's a multitenant project. There are 2 paths: kubernetes and a custom architecture. To build a custom architecture the app must be on a few virtual machines, a load balancer on top including firewall. The challenge: ask me necessary questions so we could make a right decision. I have to highlight, we build a users' environment, not the product architecture I will create in order to reproduce the given environment, so we need to decide that would fit me and users better."})]}),"\n",(0,a.jsx)(t.p,{children:"Initially I thought I will do it providing a user set of virtual machines connected under VPC, putting a load balancer on top, back to 2000. I thought it will make it cheaper and some tools just easier to implement."}),"\n",(0,a.jsxs)(t.p,{children:["Chatting to GPT I realized - Kubernetes will provide it a way quicker, most of the stuff is just ready to go like network policies, load balancing, SSL, deployment/rollback, health monitoring, resources observability, Istio adoption. Istio is very useful for observability and local first development, it became a new word today - ",(0,a.jsx)(t.strong,{children:"remocal"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"When stepped into the planning I decided to make it even longer.\nI wanted to researched all the kanban boards, unresistable.\nI used to use Trello and it was ok, but using api in power-ups boundaries sucks. Not really somethign I need right now though."}),"\n",(0,a.jsx)(t.p,{children:"I tried Cluckup, it's a laggish joke, even worse than Jira to make you feel you are already enterprise.\nI tried Asana and saw 0 difference with Trello, I spent about 2 minutes to confirm it and exist."}),"\n",(0,a.jsx)(t.h3,{id:"the-ugly-thing",children:"The ugly thing"}),"\n",(0,a.jsx)(t.p,{children:"In the end I found Linear.\nTo be fair it looked ugly, the design is equal to supabase: fonts, buttons."}),"\n",(0,a.jsx)(t.p,{children:"A few minutes later I started catching.\nKeyboard first design - that's what I buy."}),"\n",(0,a.jsx)(t.p,{children:"So I read Linear Method, the framework they apply internally. It was hard to accept it, I think older I get more conservatibe I become, but I dig it anyway.\nThe basic element is an issue. It might have sub-issues. And they might have.\nThey can be collected in a project."}),"\n",(0,a.jsx)(t.p,{children:"There are bunch of other staff I don't use, but I will share it below."}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"Cycle - like a sprint, hate it."}),"\n",(0,a.jsx)(t.li,{children:"Triage - inbox, it's a boss feature in my opinion, you can aggregate communication channels in a single place, then an on-call person can carry them, create issues or remove."}),"\n",(0,a.jsx)(t.li,{children:"Initiative - collection of the projects, they can be presented as a time line or a strategy decision, or even a roadmap on a timeline."}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"As a result I cooked quite a few cards (48 projects in a backlog \ud83d\ude31\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f)."}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(4753).Z+"",width:"1632",height:"1121"})}),"\n",(0,a.jsxs)(t.p,{children:["Thank you for reading, come here and see what's gonna be in the end.\nRepository is here: ",(0,a.jsx)(t.a,{href:"http://github.com/treenq/treenq",children:"http://github.com/treenq/treenq"})]})]})}function h(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},4753:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/few-a8829c782e27ba5f7f88f18ced787cf4.png"},8323:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/gpt-b6084e0c9c75c7a74f335fb999dde350.png"},1151:(e,t,n)=>{n.d(t,{Z:()=>r,a:()=>s});var a=n(7294);const i={},o=a.createContext(i);function s(e){const t=a.useContext(o);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),a.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5ea76644.65448e33.js b/assets/js/5ea76644.65448e33.js new file mode 100644 index 0000000..35f34f3 --- /dev/null +++ b/assets/js/5ea76644.65448e33.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[644],{8826:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var a=n(5893),i=n(1151);const o={slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},r=void 0,s={permalink:"/mynameis/blog/tq-devlog-0",source:"@site/blog/04-tq-devlog-0/index.md",title:"PaaS devlog |#0",description:"Devlog |#0",date:"2024-09-02T20:12:28.000Z",formattedDate:"September 2, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.955,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},unlisted:!1,prevItem:{title:"PaaS devlog |#1",permalink:"/mynameis/blog/tq-devlog-1"},nextItem:{title:"Backend Guy Ventures into Game Development",permalink:"/mynameis/blog/do-gamedev"}},l={authorsImageUrls:[void 0]},d=[{value:"Devlog |#0",id:"devlog-0",level:2},{value:"The problem",id:"the-problem",level:3},{value:"The planing",id:"the-planing",level:3},{value:"The ugly thing",id:"the-ugly-thing",level:3}];function c(e){const t={a:"a",admonition:"admonition",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.a)(),...e.components},{Details:o}=t;return o||function(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"devlog-0",children:"Devlog |#0"}),"\n",(0,a.jsx)(t.p,{children:"Today I want to share with you my first steps of creating new project.\nFor a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service."}),"\n",(0,a.jsx)(t.p,{children:"The main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration."}),"\n",(0,a.jsx)(t.admonition,{type:"tip",children:(0,a.jsxs)(t.p,{children:["You can read more about cdk ",(0,a.jsx)(t.a,{href:"https://developer.hashicorp.com/terraform/cdktf",children:"here"})]})}),"\n",(0,a.jsx)(t.p,{children:"All the infra will be used from a well known cloud providers (not aws ofc, no clue who can understand how to user it).\nFirst iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me."}),"\n",(0,a.jsx)(t.h3,{id:"the-problem",children:"The problem"}),"\n",(0,a.jsxs)(t.p,{children:["The technical problem exists, it's fun to figure out.\nBut no the main one. The biggest fight Im gonna accept is ",(0,a.jsx)(t.strong,{children:"procrastination"}),". Im such a person who pushes further all the tasks very often. I just have little to do with time discipline. That's what will stop me from the progress.\nSo the easiest way to move progress away - do whatever, but not the progress."]}),"\n",(0,a.jsx)(t.h3,{id:"the-planing",children:"The planing"}),"\n",(0,a.jsxs)(t.p,{children:["So I decided to plan everything and understand how big the actual project is gonna be.\nSo I start speaking with GPT in order to express my mind, kinda talking to a duck.\nInstead of asking what I should do I explained my plan and asked to ask ",(0,a.jsx)(t.strong,{children:"more questions"})," so it could help me to clarify the technical solution and the plan."]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(8323).Z+"",width:"817",height:"1036"})}),"\n",(0,a.jsxs)(o,{children:[(0,a.jsx)("summary",{children:(0,a.jsx)(t.p,{children:"Here you can find a prompt I used"})}),(0,a.jsx)(t.p,{children:"I want to develop a platform like digitalocean app, vercel, render, fly.io, heroku, etc. My value is the following: I give observability with 0 code changes, and a localdev opportunity with connecting to a cloud environment, for instance a request comes from a frontend app on staging to my backend app locally so I could intercept it and make my laptop appear kinda in the cloud. It's a multitenant project. There are 2 paths: kubernetes and a custom architecture. To build a custom architecture the app must be on a few virtual machines, a load balancer on top including firewall. The challenge: ask me necessary questions so we could make a right decision. I have to highlight, we build a users' environment, not the product architecture I will create in order to reproduce the given environment, so we need to decide that would fit me and users better."})]}),"\n",(0,a.jsx)(t.p,{children:"Initially I thought I will do it providing a user set of virtual machines connected under VPC, putting a load balancer on top, back to 2000. I thought it will make it cheaper and some tools just easier to implement."}),"\n",(0,a.jsxs)(t.p,{children:["Chatting to GPT I realized - Kubernetes will provide it a way quicker, most of the stuff is just ready to go like network policies, load balancing, SSL, deployment/rollback, health monitoring, resources observability, Istio adoption. Istio is very useful for observability and local first development, it became a new word today - ",(0,a.jsx)(t.strong,{children:"remocal"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"When stepped into the planning I decided to make it even longer.\nI wanted to researched all the kanban boards, unresistable.\nI used to use Trello and it was ok, but using api in power-ups boundaries sucks. Not really somethign I need right now though."}),"\n",(0,a.jsx)(t.p,{children:"I tried Cluckup, it's a laggish joke, even worse than Jira to make you feel you are already enterprise.\nI tried Asana and saw 0 difference with Trello, I spent about 2 minutes to confirm it and exist."}),"\n",(0,a.jsx)(t.h3,{id:"the-ugly-thing",children:"The ugly thing"}),"\n",(0,a.jsx)(t.p,{children:"In the end I found Linear.\nTo be fair it looked ugly, the design is equal to supabase: fonts, buttons."}),"\n",(0,a.jsx)(t.p,{children:"A few minutes later I started catching.\nKeyboard first design - that's what I buy."}),"\n",(0,a.jsx)(t.p,{children:"So I read Linear Method, the framework they apply internally. It was hard to accept it, I think older I get more conservatibe I become, but I dig it anyway.\nThe basic element is an issue. It might have sub-issues. And they might have.\nThey can be collected in a project."}),"\n",(0,a.jsx)(t.p,{children:"There are bunch of other staff I don't use, but I will share it below."}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"Cycle - like a sprint, hate it."}),"\n",(0,a.jsx)(t.li,{children:"Triage - inbox, it's a boss feature in my opinion, you can aggregate communication channels in a single place, then an on-call person can carry them, create issues or remove."}),"\n",(0,a.jsx)(t.li,{children:"Initiative - collection of the projects, they can be presented as a time line or a strategy decision, or even a roadmap on a timeline."}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"As a result I cooked quite a few cards (48 projects in a backlog \ud83d\ude31\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f)."}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(4753).Z+"",width:"1632",height:"1121"})}),"\n",(0,a.jsxs)(t.p,{children:["Thank you for reading, come here and see what's gonna be in the end.\nRepository is here: ",(0,a.jsx)(t.a,{href:"http://github.com/treenq/treenq",children:"http://github.com/treenq/treenq"})]})]})}function h(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},4753:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/few-a8829c782e27ba5f7f88f18ced787cf4.png"},8323:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/gpt-b6084e0c9c75c7a74f335fb999dde350.png"},1151:(e,t,n)=>{n.d(t,{Z:()=>s,a:()=>r});var a=n(7294);const i={},o=a.createContext(i);function r(e){const t=a.useContext(o);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function s(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6c979130.d4282b76.js b/assets/js/6c979130.c4f72816.js similarity index 77% rename from assets/js/6c979130.d4282b76.js rename to assets/js/6c979130.c4f72816.js index 59a1ce3..a7c0640 100644 --- a/assets/js/6c979130.d4282b76.js +++ b/assets/js/6c979130.c4f72816.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[68],{7045:s=>{s.exports=JSON.parse('{"label":"software","permalink":"/mynameis/blog/tags/software","allTagsPath":"/mynameis/blog/tags","count":3,"unlisted":false}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[68],{7045:s=>{s.exports=JSON.parse('{"label":"software","permalink":"/mynameis/blog/tags/software","allTagsPath":"/mynameis/blog/tags","count":4,"unlisted":false}')}}]); \ No newline at end of file diff --git a/assets/js/814f3328.5d4dc5d0.js b/assets/js/814f3328.5d4dc5d0.js deleted file mode 100644 index e969f55..0000000 --- a/assets/js/814f3328.5d4dc5d0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[535],{5641:e=>{e.exports=JSON.parse('{"title":"Recent posts","items":[{"title":"PaaS devlog |#0","permalink":"/mynameis/blog/tq-devlog-0","unlisted":false},{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev","unlisted":false},{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json","unlisted":false},{"title":"Why this page exists","permalink":"/mynameis/blog/why-a-blog","unlisted":false}]}')}}]); \ No newline at end of file diff --git a/assets/js/814f3328.bbd20a50.js b/assets/js/814f3328.bbd20a50.js new file mode 100644 index 0000000..640ffe0 --- /dev/null +++ b/assets/js/814f3328.bbd20a50.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[535],{5641:e=>{e.exports=JSON.parse('{"title":"Recent posts","items":[{"title":"PaaS devlog |#1","permalink":"/mynameis/blog/tq-devlog-1","unlisted":false},{"title":"PaaS devlog |#0","permalink":"/mynameis/blog/tq-devlog-0","unlisted":false},{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev","unlisted":false},{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json","unlisted":false},{"title":"Why this page exists","permalink":"/mynameis/blog/why-a-blog","unlisted":false}]}')}}]); \ No newline at end of file diff --git a/assets/js/b7209ac4.c6f71f80.js b/assets/js/b7209ac4.a1d73d79.js similarity index 75% rename from assets/js/b7209ac4.c6f71f80.js rename to assets/js/b7209ac4.a1d73d79.js index 3ca06f3..e964727 100644 --- a/assets/js/b7209ac4.c6f71f80.js +++ b/assets/js/b7209ac4.a1d73d79.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[4],{3203:e=>{e.exports=JSON.parse('{"permalink":"/mynameis/blog/tags/software","page":1,"postsPerPage":10,"totalPages":1,"totalCount":3,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[4],{3203:e=>{e.exports=JSON.parse('{"permalink":"/mynameis/blog/tags/software","page":1,"postsPerPage":10,"totalPages":1,"totalCount":4,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/assets/js/dfd01fac.69c1ff4f.js b/assets/js/dfd01fac.69c1ff4f.js new file mode 100644 index 0000000..070a6c5 --- /dev/null +++ b/assets/js/dfd01fac.69c1ff4f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[24],{8956:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>m,frontMatter:()=>r,metadata:()=>i,toc:()=>c});var o=n(5893),a=n(1151);const r={slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},s=void 0,i={permalink:"/mynameis/blog/tq-devlog-1",source:"@site/blog/05-tq-devlog-1/index.md",title:"PaaS devlog |#1",description:"Devlog |#1",date:"2024-09-03T18:48:09.000Z",formattedDate:"September 3, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.295,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},unlisted:!1,nextItem:{title:"PaaS devlog |#0",permalink:"/mynameis/blog/tq-devlog-0"}},l={authorsImageUrls:[void 0]},c=[{value:"Devlog |#1",id:"devlog-1",level:2}];function d(e){const t={h2:"h2",p:"p",...(0,a.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h2,{id:"devlog-1",children:"Devlog |#1"}),"\n",(0,o.jsx)(t.p,{children:"Another day I actually started working on the project (what a surprise)."}),"\n",(0,o.jsx)(t.p,{children:"I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more."})]})}function m(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>i,a:()=>s});var o=n(7294);const a={},r=o.createContext(a);function s(e){const t=o.useContext(r);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),o.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/main.63e99e91.js b/assets/js/main.63e99e91.js deleted file mode 100644 index 59174f4..0000000 --- a/assets/js/main.63e99e91.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see main.63e99e91.js.LICENSE.txt */ -(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[179],{723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});n(7294);var r=n(8356),a=n.n(r),o=n(6887);const i={"01a85c17":[()=>Promise.all([n.e(532),n.e(13)]).then(n.bind(n,1223)),"@theme/BlogTagsListPage",1223],"0c073a7b":[()=>n.e(445).then(n.t.bind(n,124,19)),"~blog/default/mynameis-blog-tags-tags-65e.json",124],"0e2cd4ea":[()=>n.e(925).then(n.bind(n,4721)),"@site/blog/03-do-gamedev/index.mdx",4721],"0e5f3422":[()=>n.e(977).then(n.bind(n,8671)),"@site/blog/01-why-you-need-a-blog/index.mdx",8671],"11ca47d7":[()=>n.e(170).then(n.t.bind(n,4816,19)),"~blog/default/mynameis-blog-tags-career-318-list.json",4816],"1a1195cb":[()=>n.e(531).then(n.bind(n,7115)),"@site/blog/04-tq-devlog-0/index.md?truncated=true",7115],"1df93b7f":[()=>Promise.all([n.e(532),n.e(154),n.e(237)]).then(n.bind(n,3808)),"@site/src/pages/index.tsx",3808],"1f391b9e":[()=>Promise.all([n.e(532),n.e(196),n.e(85)]).then(n.bind(n,4247)),"@theme/MDXPage",4247],"24ca0b60":[()=>n.e(831).then(n.t.bind(n,5745,19)),"/Users/denis/projects/mynameis/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",5745],"27df296f":[()=>n.e(806).then(n.t.bind(n,1746,19)),"~blog/default/mynameis-blog-tags-career-318.json",1746],"2e217b76":[()=>n.e(682).then(n.t.bind(n,304,19)),"~blog/default/mynameis-blog-ea0.json",304],"2f6ea139":[()=>n.e(538).then(n.t.bind(n,6362,19)),"~blog/default/mynameis-blog-archive-e7e.json",6362],"367c4eda":[()=>n.e(883).then(n.bind(n,3063)),"@site/blog/01-why-you-need-a-blog/index.mdx?truncated=true",3063],"393be207":[()=>n.e(414).then(n.bind(n,461)),"@site/src/pages/markdown-page.md",461],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,6809)),"@generated/docusaurus.config",6809],"5ea76644":[()=>n.e(644).then(n.bind(n,8826)),"@site/blog/04-tq-devlog-0/index.md",8826],"6875c492":[()=>Promise.all([n.e(532),n.e(196),n.e(748),n.e(610)]).then(n.bind(n,1714)),"@theme/BlogTagsPostsPage",1714],"6c979130":[()=>n.e(68).then(n.t.bind(n,7045,19)),"~blog/default/mynameis-blog-tags-software-f75.json",7045],"7bdc3b36":[()=>n.e(675).then(n.bind(n,7161)),"@site/blog/02-250mbjson-in-50mb-limit/index.mdx?truncated=true",7161],"814f3328":[()=>n.e(535).then(n.t.bind(n,5641,19)),"~blog/default/blog-post-list-prop-default.json",5641],"9e4087bc":[()=>n.e(608).then(n.bind(n,3169)),"@theme/BlogArchivePage",3169],a6aa9e1f:[()=>Promise.all([n.e(532),n.e(196),n.e(748),n.e(89)]).then(n.bind(n,46)),"@theme/BlogListPage",46],b7209ac4:[()=>n.e(4).then(n.t.bind(n,3203,19)),"~blog/default/mynameis-blog-tags-software-f75-list.json",3203],c5a8c89d:[()=>n.e(779).then(n.bind(n,7828)),"@site/blog/03-do-gamedev/index.mdx?truncated=true",7828],ccc49370:[()=>Promise.all([n.e(532),n.e(196),n.e(748),n.e(103)]).then(n.bind(n,5203)),"@theme/BlogPostPage",5203],e37f4f80:[()=>n.e(343).then(n.bind(n,1232)),"@site/blog/02-250mbjson-in-50mb-limit/index.mdx",1232],e79bf1a2:[()=>n.e(837).then(n.t.bind(n,4469,19)),"/Users/denis/projects/mynameis/.docusaurus/docusaurus-plugin-content-blog/default/plugin-route-context-module-100.json",4469]};var l=n(5893);function s(e){let{error:t,retry:n,pastDelay:r}=e;return t?(0,l.jsxs)("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"},children:[(0,l.jsx)("p",{children:String(t)}),(0,l.jsx)("div",{children:(0,l.jsx)("button",{type:"button",onClick:n,children:"Retry"})})]}):r?(0,l.jsx)("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:(0,l.jsx)("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb",children:(0,l.jsxs)("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2",children:[(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsx)("circle",{cx:"22",cy:"22",r:"8",children:(0,l.jsx)("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"})})]})})}):null}var u=n(9670),c=n(226);function d(e,t){if("*"===e)return a()({loading:s,loader:()=>n.e(460).then(n.bind(n,1460)),modules:["@theme/NotFound"],webpack:()=>[1460],render(e,t){const n=e.default;return(0,l.jsx)(c.z,{value:{plugin:{name:"native",id:"default"}},children:(0,l.jsx)(n,{...t})})}});const r=o[`${e}-${t}`],d={},p=[],f=[],m=(0,u.Z)(r);return Object.entries(m).forEach((e=>{let[t,n]=e;const r=i[n];r&&(d[t]=r[0],p.push(r[1]),f.push(r[2]))})),a().Map({loading:s,loader:d,modules:p,webpack:()=>f,render(t,n){const a=JSON.parse(JSON.stringify(r));Object.entries(t).forEach((t=>{let[n,r]=t;const o=r.default;if(!o)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof o&&"function"!=typeof o||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{o[e]=r[e]}));let i=a;const l=n.split(".");l.slice(0,-1).forEach((e=>{i=i[e]})),i[l[l.length-1]]=o}));const o=a.__comp;delete a.__comp;const i=a.__context;return delete a.__context,(0,l.jsx)(c.z,{value:i,children:(0,l.jsx)(o,{...a,...n})})}})}const p=[{path:"/mynameis/blog",component:d("/mynameis/blog","d52"),exact:!0},{path:"/mynameis/blog/archive",component:d("/mynameis/blog/archive","af1"),exact:!0},{path:"/mynameis/blog/big-json",component:d("/mynameis/blog/big-json","8c1"),exact:!0},{path:"/mynameis/blog/do-gamedev",component:d("/mynameis/blog/do-gamedev","e11"),exact:!0},{path:"/mynameis/blog/tags",component:d("/mynameis/blog/tags","30b"),exact:!0},{path:"/mynameis/blog/tags/career",component:d("/mynameis/blog/tags/career","856"),exact:!0},{path:"/mynameis/blog/tags/software",component:d("/mynameis/blog/tags/software","b0b"),exact:!0},{path:"/mynameis/blog/tq-devlog-0",component:d("/mynameis/blog/tq-devlog-0","ba9"),exact:!0},{path:"/mynameis/blog/why-a-blog",component:d("/mynameis/blog/why-a-blog","fa7"),exact:!0},{path:"/mynameis/markdown-page",component:d("/mynameis/markdown-page","5db"),exact:!0},{path:"/mynameis/",component:d("/mynameis/","f42"),exact:!0},{path:"*",component:d("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>o,t:()=>i});var r=n(7294),a=n(5893);const o=r.createContext(!1);function i(e){let{children:t}=e;const[n,i]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{i(!0)}),[]),(0,a.jsx)(o.Provider,{value:n,children:t})}},6888:(e,t,n)=>{"use strict";var r=n(7294),a=n(745),o=n(3727),i=n(405),l=n(412);const s=[n(2497),n(3310),n(8320),n(2295)];var u=n(723),c=n(6550),d=n(7462);function p(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var r=e.path?(0,c.LX)(t,e):n.length?n[n.length-1].match:c.F0.computeRootMatch(t);return r&&(n.push({route:e,match:r}),e.routes&&p(e.routes,t,n)),r})),n}var f=n(5893);function m(e){let{children:t}=e;return(0,f.jsx)(f.Fragment,{children:t})}var g=n(5742),h=n(2263),y=n(4996),b=n(6668),v=n(1944),w=n(4711),k=n(9727);const x="default";var S=n(8780),E=n(197);function C(){const{i18n:{currentLocale:e,defaultLocale:t,localeConfigs:n}}=(0,h.Z)(),r=(0,w.l)(),a=n[e].htmlLang,o=e=>e.replace("-","_");return(0,f.jsxs)(g.Z,{children:[Object.entries(n).map((e=>{let[t,{htmlLang:n}]=e;return(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:n},t)})),(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:"x-default"}),(0,f.jsx)("meta",{property:"og:locale",content:o(a)}),Object.values(n).filter((e=>a!==e.htmlLang)).map((e=>(0,f.jsx)("meta",{property:"og:locale:alternate",content:o(e.htmlLang)},`meta-og-${e.htmlLang}`)))]})}function _(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,h.Z)(),r=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,h.Z)(),{pathname:r}=(0,c.TH)();return e+(0,S.applyTrailingSlash)((0,y.Z)(r),{trailingSlash:n,baseUrl:t})}(),a=t?`${n}${t}`:r;return(0,f.jsxs)(g.Z,{children:[(0,f.jsx)("meta",{property:"og:url",content:a}),(0,f.jsx)("link",{rel:"canonical",href:a})]})}function T(){const{i18n:{currentLocale:e}}=(0,h.Z)(),{metadata:t,image:n}=(0,b.L)();return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(g.Z,{children:[(0,f.jsx)("meta",{name:"twitter:card",content:"summary_large_image"}),(0,f.jsx)("body",{className:k.h})]}),n&&(0,f.jsx)(v.d,{image:n}),(0,f.jsx)(_,{}),(0,f.jsx)(C,{}),(0,f.jsx)(E.Z,{tag:x,locale:e}),(0,f.jsx)(g.Z,{children:t.map(((e,t)=>(0,f.jsx)("meta",{...e},t)))})]})}const j=new Map;function L(e){if(j.has(e.pathname))return{...e,pathname:j.get(e.pathname)};if(p(u.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return j.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return j.set(e.pathname,t),{...e,pathname:t}}var A=n(8934),N=n(8940),R=n(469);function P(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const O=function(e){let{children:t,location:n,previousLocation:r}=e;return(0,R.Z)((()=>{r!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,o=t.search===n.search;if(r&&a&&!o)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:r}),P("onRouteDidUpdate",{previousLocation:r,location:n}))}),[r,n]),t};function D(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>p(u.Z,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class I extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.Z.canUseDOM?P("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=P("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),D(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return(0,f.jsx)(O,{previousLocation:this.previousLocation,location:t,children:(0,f.jsx)(c.AW,{location:t,render:()=>e})})}}const F=I,M="__docusaurus-base-url-issue-banner-container",z="__docusaurus-base-url-issue-banner",B="__docusaurus-base-url-issue-banner-suggestion-container";function $(e){return`\ndocument.addEventListener('DOMContentLoaded', function maybeInsertBanner() {\n var shouldInsert = typeof window['docusaurus'] === 'undefined';\n shouldInsert && insertBanner();\n});\n\nfunction insertBanner() {\n var bannerContainer = document.createElement('div');\n bannerContainer.id = '${M}';\n var bannerHtml = ${JSON.stringify(function(e){return`\n
\n

Your Docusaurus site did not load properly.

\n

A very common reason is a wrong site baseUrl configuration.

\n

Current configured baseUrl = ${e} ${"/"===e?" (default value)":""}

\n

We suggest trying baseUrl =

\n
\n`}(e)).replace(/{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var K=n(9670);const X=new Set,J=new Set,ee=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,te={prefetch(e){if(!(e=>!ee()&&!J.has(e)&&!X.has(e))(e))return!1;X.add(e);const t=p(u.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(Q).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,K.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?Y(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!ee()&&!J.has(e))(e)&&(J.add(e),D(e))},ne=Object.freeze(te),re=Boolean(!0);if(l.Z.canUseDOM){window.docusaurus=ne;const e=document.getElementById("__docusaurus"),t=(0,f.jsx)(i.B6,{children:(0,f.jsx)(o.VK,{children:(0,f.jsx)(W,{})})}),n=(e,t)=>{console.error("Docusaurus React Root onRecoverableError:",e,t)},l=()=>{if(re)r.startTransition((()=>{a.hydrateRoot(e,t,{onRecoverableError:n})}));else{const o=a.createRoot(e,{onRecoverableError:n});r.startTransition((()=>{o.render(t)}))}};D(window.location.pathname).then(l)}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>c,M:()=>d});var r=n(7294),a=n(6809);const o=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var i=n(7529);const l=JSON.parse('{"docusaurusVersion":"3.0.1","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"3.0.1"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"3.0.1"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"3.0.1"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"3.0.1"}}}');var s=n(5893);const u={siteConfig:a.default,siteMetadata:l,globalData:{},i18n:o,codeTranslations:i},c=r.createContext(u);function d(e){let{children:t}=e;return(0,s.jsx)(c.Provider,{value:u,children:t})}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(412),o=n(5742),i=n(8780),l=n(2593),s=n(5893);function u(e){let{error:t,tryAgain:n}=e;return(0,s.jsxs)("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"},children:[(0,s.jsx)("h1",{style:{fontSize:"3rem"},children:"This page crashed"}),(0,s.jsx)("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"},children:"Try again"}),(0,s.jsx)(c,{error:t})]})}function c(e){let{error:t}=e;const n=(0,i.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,s.jsx)("p",{style:{whiteSpace:"pre-wrap"},children:n})}function d(e){let{error:t,tryAgain:n}=e;return(0,s.jsxs)(f,{fallback:()=>(0,s.jsx)(u,{error:t,tryAgain:n}),children:[(0,s.jsx)(o.Z,{children:(0,s.jsx)("title",{children:"Page Error"})}),(0,s.jsx)(l.Z,{children:(0,s.jsx)(u,{error:t,tryAgain:n})})]})}const p=e=>(0,s.jsx)(d,{...e});class f extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??p)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});n(7294);var r=n(405),a=n(5893);function o(e){return(0,a.jsx)(r.ql,{...e})}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(3727),o=n(8780),i=n(2263),l=n(3919),s=n(412),u=n(5893);const c=r.createContext({collectLink:()=>{}});var d=n(4996);function p(e,t){let{isNavLink:n,to:p,href:f,activeClassName:m,isActive:g,"data-noBrokenLinkCheck":h,autoAddBaseUrl:y=!0,...b}=e;const{siteConfig:{trailingSlash:v,baseUrl:w}}=(0,i.Z)(),{withBaseUrl:k}=(0,d.C)(),x=(0,r.useContext)(c),S=(0,r.useRef)(null);(0,r.useImperativeHandle)(t,(()=>S.current));const E=p||f;const C=(0,l.Z)(E),_=E?.replace("pathname://","");let T=void 0!==_?(j=_,y&&(e=>e.startsWith("/"))(j)?k(j):j):void 0;var j;T&&C&&(T=(0,o.applyTrailingSlash)(T,{trailingSlash:v,baseUrl:w}));const L=(0,r.useRef)(!1),A=n?a.OL:a.rU,N=s.Z.canUseIntersectionObserver,R=(0,r.useRef)(),P=()=>{L.current||null==T||(window.docusaurus.preload(T),L.current=!0)};(0,r.useEffect)((()=>(!N&&C&&null!=T&&window.docusaurus.prefetch(T),()=>{N&&R.current&&R.current.disconnect()})),[R,T,N,C]);const O=T?.startsWith("#")??!1,D=!T||!C||O;return D||h||x.collectLink(T),D?(0,u.jsx)("a",{ref:S,href:T,...E&&!C&&{target:"_blank",rel:"noopener noreferrer"},...b}):(0,u.jsx)(A,{...b,onMouseEnter:P,onTouchStart:P,innerRef:e=>{S.current=e,N&&e&&C&&(R.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(R.current.unobserve(e),R.current.disconnect(),null!=T&&window.docusaurus.prefetch(T))}))})),R.current.observe(e))},to:T,...n&&{isActive:g,activeClassName:m}})}const f=r.forwardRef(p)},1875:(e,t,n)=>{"use strict";n.d(t,{Z:()=>r});const r=()=>null},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u,I:()=>s});var r=n(7294),a=n(5893);function o(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var i=n(7529);function l(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return i[t??n]??n??t}function s(e,t){let{message:n,id:r}=e;return o(l({message:n,id:r}),t)}function u(e){let{children:t,id:n,values:r}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal children",t),new Error("The Docusaurus component only accept simple string values");const i=l({message:t,id:n});return(0,a.jsx)(a.Fragment,{children:o(i,r)})}},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>a,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>i,Z:()=>l});var r=n(7294),a=n(2263),o=n(3919);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function l(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8940);function o(){return(0,r.useContext)(a._)}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8934);function o(){return(0,r.useContext)(a._)}},469:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(7294);const a=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t={};return function e(n,a){Object.entries(n).forEach((n=>{let[o,i]=n;const l=a?`${a}.${o}`:o;r(i)?e(i,l):t[l]=i}))}(e),t}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>o,z:()=>i});var r=n(7294),a=n(5893);const o=r.createContext(null);function i(e){let{children:t,value:n}=e;const i=r.useContext(o),l=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:i,value:n})),[i,n]);return(0,a.jsx)(o.Provider,{value:l,children:t})}},8320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});const o={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(2573),a=n(6809);!function(e){const{themeConfig:{prism:t}}=a.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{"php"===e&&n(6854),n(6726)(`./prism-${e}`)})),delete globalThis.Prism}(r.p1)},2503:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});n(7294);var r=n(512),a=n(5999),o=n(6668),i=n(9960);const l={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};var s=n(5893);function u(e){let{as:t,id:n,...u}=e;const{navbar:{hideOnScroll:c}}=(0,o.L)();if("h1"===t||!n)return(0,s.jsx)(t,{...u,id:void 0});const d=(0,a.I)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof u.children?u.children:n});return(0,s.jsxs)(t,{...u,className:(0,r.Z)("anchor",c?l.anchorWithHideOnScrollNavbar:l.anchorWithStickyNavbar,u.className),id:n,children:[u.children,(0,s.jsx)(i.Z,{className:"hash-link",to:`#${n}`,"aria-label":d,title:d,children:"\u200b"})]})}},2593:(e,t,n)=>{"use strict";n.d(t,{Z:()=>Vt});var r=n(7294),a=n(512),o=n(4763),i=n(1944),l=n(6550),s=n(5999),u=n(902);function c(e){const t=(0,l.TH)(),n=(0,u.D9)(t),a=(0,u.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&a({location:t,previousLocation:n})}),[a,t,n])}var d=n(5893);const p="__docusaurus_skipToContent_fallback";function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function m(){const e=(0,r.useRef)(null),{action:t}=(0,l.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(p);t&&f(t)}),[]);return c((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&f(e.current)})),{containerRef:e,onClick:n}}const g=(0,s.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function h(e){const t=e.children??g,{containerRef:n,onClick:r}=m();return(0,d.jsx)("div",{ref:n,role:"region","aria-label":g,children:(0,d.jsx)("a",{...e,href:`#${p}`,onClick:r,children:t})})}var y=n(5281),b=n(9727);const v={skipToContent:"skipToContent_fXgn"};function w(){return(0,d.jsx)(h,{className:v.skipToContent})}var k=n(6668),x=n(2389),S=n(12);const E=(0,S.WA)("docusaurus.announcement.dismiss"),C=(0,S.WA)("docusaurus.announcement.id"),_=()=>"true"===E.get(),T=e=>E.set(String(e)),j=r.createContext(null);function L(e){let{width:t=21,height:n=21,color:r="currentColor",strokeWidth:a=1.2,className:o,...i}=e;return(0,d.jsx)("svg",{viewBox:"0 0 15 15",width:t,height:n,...i,children:(0,d.jsx)("g",{stroke:r,strokeWidth:a,children:(0,d.jsx)("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})})})}const A={closeButton:"closeButton_CVFx"};function N(e){return(0,d.jsx)("button",{type:"button","aria-label":(0,s.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"}),...e,className:(0,a.Z)("clean-btn close",A.closeButton,e.className),children:(0,d.jsx)(L,{width:14,height:14,strokeWidth:3.1})})}const R={content:"content_knG7"};function P(e){const{announcementBar:t}=(0,k.L)(),{content:n}=t;return(0,d.jsx)("div",{...e,className:(0,a.Z)(R.content,e.className),dangerouslySetInnerHTML:{__html:n}})}const O={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function D(){const{announcementBar:e}=(0,k.L)(),{isActive:t,close:n}=function(){const e=(0,r.useContext)(j);if(!e)throw new u.i6("AnnouncementBarProvider");return e}();if(!t)return null;const{backgroundColor:a,textColor:o,isCloseable:i}=e;return(0,d.jsxs)("div",{className:O.announcementBar,style:{backgroundColor:a,color:o},role:"banner",children:[i&&(0,d.jsx)("div",{className:O.announcementBarPlaceholder}),(0,d.jsx)(P,{className:O.announcementBarContent}),i&&(0,d.jsx)(N,{onClick:n,className:O.announcementBarClose})]})}var I=n(3102),F=n(7524);function M(e){!function(e){const t=(0,l.k6)(),n=(0,u.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}const z=r.createContext(void 0);function B(){const e=function(){const e=(0,I.HY)(),{items:t}=(0,k.L)().navbar;return 0===t.length&&!e.component}(),t=(0,F.i)(),n=!e&&"mobile"===t,[a,o]=(0,r.useState)(!1);M((()=>{if(a)return o(!1),!1}));const i=(0,r.useCallback)((()=>{o((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&o(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:i,shown:a})),[e,n,i,a])}function $(e){let{children:t}=e;const n=B();return(0,d.jsx)(z.Provider,{value:n,children:t})}function U(){const e=r.useContext(z);if(void 0===e)throw new u.i6("NavbarMobileSidebarProvider");return e}var q=n(412);n(469);const H=r.createContext(void 0);function Z(){const e=(0,r.useContext)(H);if(null==e)throw new u.i6("ScrollControllerProvider");return e}const G=()=>q.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function V(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),o=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(o.current=e.getBoundingClientRect().height)}),[]);return function(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=Z(),a=(0,r.useRef)(G()),o=(0,u.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=G();o(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[o,n,...t])}(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i=l?n(!1):i+u{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}const W=r.createContext(null);function Q(e){let{children:t}=e;const n=function(){const e=U(),t=(0,I.HY)(),[n,a]=(0,r.useState)(!1),o=null!==t.component,i=(0,u.D9)(o);return(0,r.useEffect)((()=>{o&&!i&&a(!0)}),[o,i]),(0,r.useEffect)((()=>{o?e.shown||a(!0):a(!1)}),[e.shown,o]),(0,r.useMemo)((()=>[n,a]),[n])}();return(0,d.jsx)(W.Provider,{value:n,children:t})}function Y(e){if(e.component){const t=e.component;return(0,d.jsx)(t,{...e.props})}}function K(){const e=(0,r.useContext)(W);if(!e)throw new u.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),o=(0,I.HY)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:Y(o)})),[a,o,t])}function X(e){let{header:t,primaryMenu:n,secondaryMenu:r}=e;const{shown:o}=K();return(0,d.jsxs)("div",{className:"navbar-sidebar",children:[t,(0,d.jsxs)("div",{className:(0,a.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":o}),children:[(0,d.jsx)("div",{className:"navbar-sidebar__item menu",children:n}),(0,d.jsx)("div",{className:"navbar-sidebar__item menu",children:r})]})]})}var J=n(2949);function ee(e){return(0,d.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,d.jsx)("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"})})}function te(e){return(0,d.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,d.jsx)("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"})})}const ne={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function re(e){let{className:t,buttonClassName:n,value:r,onChange:o}=e;const i=(0,x.Z)(),l=(0,s.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===r?(0,s.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,s.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return(0,d.jsx)("div",{className:(0,a.Z)(ne.toggle,t),children:(0,d.jsxs)("button",{className:(0,a.Z)("clean-btn",ne.toggleButton,!i&&ne.toggleButtonDisabled,n),type:"button",onClick:()=>o("dark"===r?"light":"dark"),disabled:!i,title:l,"aria-label":l,"aria-live":"polite",children:[(0,d.jsx)(ee,{className:(0,a.Z)(ne.toggleIcon,ne.lightToggleIcon)}),(0,d.jsx)(te,{className:(0,a.Z)(ne.toggleIcon,ne.darkToggleIcon)})]})})}const ae=r.memo(re),oe={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function ie(e){let{className:t}=e;const n=(0,k.L)().navbar.style,r=(0,k.L)().colorMode.disableSwitch,{colorMode:a,setColorMode:o}=(0,J.I)();return r?null:(0,d.jsx)(ae,{className:t,buttonClassName:"dark"===n?oe.darkNavbarColorModeToggle:void 0,value:a,onChange:o})}var le=n(9960),se=n(4996),ue=n(2263);const ce={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};function de(e){let{className:t,children:n}=e;const o=(0,x.Z)(),{colorMode:i}=(0,J.I)();return(0,d.jsx)(d.Fragment,{children:(o?"dark"===i?["dark"]:["light"]:["light","dark"]).map((e=>{const o=n({theme:e,className:(0,a.Z)(t,ce.themedComponent,ce[`themedComponent--${e}`])});return(0,d.jsx)(r.Fragment,{children:o},e)}))})}function pe(e){const{sources:t,className:n,alt:r,...a}=e;return(0,d.jsx)(de,{className:n,children:e=>{let{theme:n,className:o}=e;return(0,d.jsx)("img",{src:t[n],alt:r,className:o,...a})}})}function fe(e){let{logo:t,alt:n,imageClassName:r}=e;const a={light:(0,se.Z)(t.src),dark:(0,se.Z)(t.srcDark||t.src)},o=(0,d.jsx)(pe,{className:t.className,sources:a,height:t.height,width:t.width,alt:n,style:t.style});return r?(0,d.jsx)("div",{className:r,children:o}):o}function me(e){const{siteConfig:{title:t}}=(0,ue.Z)(),{navbar:{title:n,logo:r}}=(0,k.L)(),{imageClassName:a,titleClassName:o,...i}=e,l=(0,se.Z)(r?.href||"/"),s=n?"":t,u=r?.alt??s;return(0,d.jsxs)(le.Z,{to:l,...i,...r?.target&&{target:r.target},children:[r&&(0,d.jsx)(fe,{logo:r,alt:u,imageClassName:a}),null!=n&&(0,d.jsx)("b",{className:o,children:n})]})}function ge(){return(0,d.jsx)(me,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function he(){const e=U();return(0,d.jsx)("button",{type:"button","aria-label":(0,s.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle(),children:(0,d.jsx)(L,{color:"var(--ifm-color-emphasis-600)"})})}function ye(){return(0,d.jsxs)("div",{className:"navbar-sidebar__brand",children:[(0,d.jsx)(ge,{}),(0,d.jsx)(ie,{className:"margin-right--md"}),(0,d.jsx)(he,{})]})}var be=n(3919);function ve(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}const we={iconExternalLink:"iconExternalLink_nPIU"};function ke(e){let{width:t=13.5,height:n=13.5}=e;return(0,d.jsx)("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:we.iconExternalLink,children:(0,d.jsx)("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"})})}function xe(e){let{activeBasePath:t,activeBaseRegex:n,to:r,href:a,label:o,html:i,isDropdownLink:l,prependBaseUrlToHref:s,...u}=e;const c=(0,se.Z)(r),p=(0,se.Z)(t),f=(0,se.Z)(a,{forcePrependBaseUrl:!0}),m=o&&a&&!(0,be.Z)(a),g=i?{dangerouslySetInnerHTML:{__html:i}}:{children:(0,d.jsxs)(d.Fragment,{children:[o,m&&(0,d.jsx)(ke,{...l&&{width:12,height:12}})]})};return a?(0,d.jsx)(le.Z,{href:s?f:a,...u,...g}):(0,d.jsx)(le.Z,{to:c,isNavLink:!0,...(t||n)&&{isActive:(e,t)=>n?ve(n,t.pathname):t.pathname.startsWith(p)},...u,...g})}function Se(e){let{className:t,isDropdownItem:n=!1,...r}=e;const o=(0,d.jsx)(xe,{className:(0,a.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n,...r});return n?(0,d.jsx)("li",{children:o}):o}function Ee(e){let{className:t,isDropdownItem:n,...r}=e;return(0,d.jsx)("li",{className:"menu__list-item",children:(0,d.jsx)(xe,{className:(0,a.Z)("menu__link",t),...r})})}function Ce(e){let{mobile:t=!1,position:n,...r}=e;const a=t?Ee:Se;return(0,d.jsx)(a,{...r,activeClassName:r.activeClassName??(t?"menu__link--active":"navbar__link--active")})}var _e=n(7186),Te=n(8596);const je={dropdownNavbarItemMobile:"dropdownNavbarItemMobile_S0Fm"};function Le(e,t){return e.some((e=>function(e,t){return!!(0,Te.Mg)(e.to,t)||!!ve(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function Ae(e){let{items:t,position:n,className:o,onClick:i,...l}=e;const s=(0,r.useRef)(null),[u,c]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{s.current&&!s.current.contains(e.target)&&c(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[s]),(0,d.jsxs)("div",{ref:s,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u}),children:[(0,d.jsx)(xe,{"aria-haspopup":"true","aria-expanded":u,role:"button",href:l.to?void 0:"#",className:(0,a.Z)("navbar__link",o),...l,onClick:l.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),c(!u))},children:l.children??l.label}),(0,d.jsx)("ul",{className:"dropdown__menu",children:t.map(((e,t)=>(0,r.createElement)(it,{isDropdownItem:!0,activeClassName:"dropdown__link--active",...e,key:t})))})]})}function Ne(e){let{items:t,className:n,position:o,onClick:i,...s}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,ue.Z)(),{pathname:t}=(0,l.TH)();return t.replace(e,"/")}(),c=Le(t,u),{collapsed:p,toggleCollapsed:f,setCollapsed:m}=(0,_e.u)({initialState:()=>!c});return(0,r.useEffect)((()=>{c&&m(!c)}),[u,c,m]),(0,d.jsxs)("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":p}),children:[(0,d.jsx)(xe,{role:"button",className:(0,a.Z)(je.dropdownNavbarItemMobile,"menu__link menu__link--sublist menu__link--sublist-caret",n),...s,onClick:e=>{e.preventDefault(),f()},children:s.children??s.label}),(0,d.jsx)(_e.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p,children:t.map(((e,t)=>(0,r.createElement)(it,{mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active",...e,key:t})))})]})}function Re(e){let{mobile:t=!1,...n}=e;const r=t?Ne:Ae;return(0,d.jsx)(r,{...n})}var Pe=n(4711);function Oe(e){let{width:t=20,height:n=20,...r}=e;return(0,d.jsx)("svg",{viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0,...r,children:(0,d.jsx)("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"})})}const De="iconLanguage_nlXk";var Ie=n(1875);const Fe={navbarSearchContainer:"navbarSearchContainer_Bca1"};function Me(e){let{children:t,className:n}=e;return(0,d.jsx)("div",{className:(0,a.Z)(n,Fe.navbarSearchContainer),children:t})}const ze="default";function Be(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,ue.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const $e=e=>e.versions.find((e=>e.isLast));function Ue(e,t){const n=function(e,t){const n=$e(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,l.LX)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),r=n?.docs.find((e=>!!(0,l.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:r,alternateDocVersions:r?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(r.id):{}}}const qe={},He=()=>Be("docusaurus-plugin-content-docs")??qe,Ze=e=>function(e,t,n){void 0===t&&(t=ze),void 0===n&&(n={});const r=Be(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0});function Ge(e){const t=Ze(e),{pathname:n}=(0,l.TH)();return Ue(t,n)}const Ve=e=>`docs-preferred-version-${e}`,We={save:(e,t,n)=>{(0,S.WA)(Ve(e),{persistence:t}).set(n)},read:(e,t)=>(0,S.WA)(Ve(e),{persistence:t}).get(),clear:(e,t)=>{(0,S.WA)(Ve(e),{persistence:t}).del()}},Qe=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const Ye=r.createContext(null);function Ke(){const e=He(),t=(0,k.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[a,o]=(0,r.useState)((()=>Qe(n)));(0,r.useEffect)((()=>{o(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=We.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(We.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[a,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){We.save(e,t,n),o((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function Xe(e){let{children:t}=e;const n=Ke();return(0,d.jsx)(Ye.Provider,{value:n,children:t})}function Je(){const e=(0,r.useContext)(Ye);if(!e)throw new u.i6("DocsPreferredVersionContextProvider");return e}function et(e){void 0===e&&(e=ze);const t=Ze(e),[n,a]=Je(),{preferredVersionName:o}=n[e];return{preferredVersion:t.versions.find((e=>e.name===o))??null,savePreferredVersionName:(0,r.useCallback)((t=>{a.savePreferredVersion(e,t)}),[a,e])}}function tt(e){return Array.from(new Set(e))}const nt=!!He;function rt(e){const{activeVersion:t}=Ge(e),{preferredVersion:n}=et(e),a=function(e){const t=Ze(e);return $e(t)}(e);return(0,r.useMemo)((()=>tt([t,n,a].filter(Boolean))),[t,n,a])}const at=e=>e.docs.find((t=>t.id===e.mainDocId));const ot={default:Ce,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:r,queryString:a="",...o}=e;const{i18n:{currentLocale:i,locales:u,localeConfigs:c}}=(0,ue.Z)(),p=(0,Pe.l)(),{search:f,hash:m}=(0,l.TH)(),g=[...n,...u.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${f}${m}${a}`;return{label:c[e].label,lang:c[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...r],h=t?(0,s.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):c[i].label;return(0,d.jsx)(Re,{...o,mobile:t,label:(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(Oe,{className:De}),h]}),items:g})},search:function(e){let{mobile:t,className:n}=e;return t?null:(0,d.jsx)(Me,{className:n,children:(0,d.jsx)(Ie.Z,{})})},dropdown:Re,html:function(e){let{value:t,className:n,mobile:r=!1,isDropdownItem:o=!1}=e;const i=o?"li":"div";return(0,d.jsx)(i,{className:(0,a.Z)({navbar__item:!r&&!o,"menu__list-item":r},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=Ge(a),l=function(e,t){const n=rt(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${tt(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}(t,a),s=i?.path===l?.path;return null===l||l.unlisted&&!s?null:(0,d.jsx)(Ce,{exact:!0,...o,isActive:()=>s||!!i?.sidebar&&i.sidebar===l.sidebar,label:n??l.id,to:l.path})},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=Ge(a),l=function(e,t){const n=rt(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}(t,a).link;if(!l)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return(0,d.jsx)(Ce,{exact:!0,...o,isActive:()=>i?.sidebar===t,label:n??l.label,to:l.path})},docsVersion:function(e){let{label:t,to:n,docsPluginId:r,...a}=e;const o=rt(r)[0],i=t??o.label,l=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(o).path;return(0,d.jsx)(Ce,{...a,label:i,to:l})},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:r,dropdownItemsBefore:a,dropdownItemsAfter:o,...i}=e;const{search:u,hash:c}=(0,l.TH)(),p=Ge(n),f=Ze(n).versions,{savePreferredVersionName:m}=et(n),g=[...a,...f.map((e=>{const t=p.alternateDocVersions[e.name]??at(e);return{label:e.label,to:`${t.path}${u}${c}`,isActive:()=>e===p.activeVersion,onClick:()=>m(e.name)}})),...o],h=rt(n)[0],y=t&&g.length>1?(0,s.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):h.label,b=t&&g.length>1?void 0:at(h).path;return g.length<=1?(0,d.jsx)(Ce,{...i,mobile:t,label:y,to:b,isActive:r?()=>!1:void 0}):(0,d.jsx)(Re,{...i,mobile:t,label:y,to:b,items:g,isActive:r?()=>!1:void 0})}};function it(e){let{type:t,...n}=e;const r=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),a=ot[r];if(!a)throw new Error(`No NavbarItem component found for type "${t}".`);return(0,d.jsx)(a,{...n})}function lt(){const e=U(),t=(0,k.L)().navbar.items;return(0,d.jsx)("ul",{className:"menu__list",children:t.map(((t,n)=>(0,r.createElement)(it,{mobile:!0,...t,onClick:()=>e.toggle(),key:n})))})}function st(e){return(0,d.jsx)("button",{...e,type:"button",className:"clean-btn navbar-sidebar__back",children:(0,d.jsx)(s.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)",children:"\u2190 Back to main menu"})})}function ut(){const e=0===(0,k.L)().navbar.items.length,t=K();return(0,d.jsxs)(d.Fragment,{children:[!e&&(0,d.jsx)(st,{onClick:()=>t.hide()}),t.content]})}function ct(){const e=U();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?(0,d.jsx)(X,{header:(0,d.jsx)(ye,{}),primaryMenu:(0,d.jsx)(lt,{}),secondaryMenu:(0,d.jsx)(ut,{})}):null}const dt={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function pt(e){return(0,d.jsx)("div",{role:"presentation",...e,className:(0,a.Z)("navbar-sidebar__backdrop",e.className)})}function ft(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:r}}=(0,k.L)(),o=U(),{navbarRef:i,isNavbarVisible:l}=V(n);return(0,d.jsxs)("nav",{ref:i,"aria-label":(0,s.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.Z)("navbar","navbar--fixed-top",n&&[dt.navbarHideable,!l&&dt.navbarHidden],{"navbar--dark":"dark"===r,"navbar--primary":"primary"===r,"navbar-sidebar--show":o.shown}),children:[t,(0,d.jsx)(pt,{onClick:o.toggle}),(0,d.jsx)(ct,{})]})}var mt=n(8780);const gt={errorBoundaryError:"errorBoundaryError_a6uf",errorBoundaryFallback:"errorBoundaryFallback_VBag"};function ht(e){return(0,d.jsx)("button",{type:"button",...e,children:(0,d.jsx)(s.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error",children:"Try again"})})}function yt(e){let{error:t}=e;const n=(0,mt.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,d.jsx)("p",{className:gt.errorBoundaryError,children:n})}class bt extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const vt="right";function wt(e){let{width:t=30,height:n=30,className:r,...a}=e;return(0,d.jsx)("svg",{className:r,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true",...a,children:(0,d.jsx)("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"})})}function kt(){const{toggle:e,shown:t}=U();return(0,d.jsx)("button",{onClick:e,"aria-label":(0,s.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button",children:(0,d.jsx)(wt,{})})}const xt={colorModeToggle:"colorModeToggle_DEke"};function St(e){let{items:t}=e;return(0,d.jsx)(d.Fragment,{children:t.map(((e,t)=>(0,d.jsx)(bt,{onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t}),children:(0,d.jsx)(it,{...e})},t)))})}function Et(e){let{left:t,right:n}=e;return(0,d.jsxs)("div",{className:"navbar__inner",children:[(0,d.jsx)("div",{className:"navbar__items",children:t}),(0,d.jsx)("div",{className:"navbar__items navbar__items--right",children:n})]})}function Ct(){const e=U(),t=(0,k.L)().navbar.items,[n,r]=function(e){function t(e){return"left"===(e.position??vt)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),a=t.find((e=>"search"===e.type));return(0,d.jsx)(Et,{left:(0,d.jsxs)(d.Fragment,{children:[!e.disabled&&(0,d.jsx)(kt,{}),(0,d.jsx)(ge,{}),(0,d.jsx)(St,{items:n})]}),right:(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(St,{items:r}),(0,d.jsx)(ie,{className:xt.colorModeToggle}),!a&&(0,d.jsx)(Me,{children:(0,d.jsx)(Ie.Z,{})})]})})}function _t(){return(0,d.jsx)(ft,{children:(0,d.jsx)(Ct,{})})}function Tt(e){let{item:t}=e;const{to:n,href:r,label:a,prependBaseUrlToHref:o,...i}=t,l=(0,se.Z)(n),s=(0,se.Z)(r,{forcePrependBaseUrl:!0});return(0,d.jsxs)(le.Z,{className:"footer__link-item",...r?{href:o?s:r}:{to:l},...i,children:[a,r&&!(0,be.Z)(r)&&(0,d.jsx)(ke,{})]})}function jt(e){let{item:t}=e;return t.html?(0,d.jsx)("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):(0,d.jsx)("li",{className:"footer__item",children:(0,d.jsx)(Tt,{item:t})},t.href??t.to)}function Lt(e){let{column:t}=e;return(0,d.jsxs)("div",{className:"col footer__col",children:[(0,d.jsx)("div",{className:"footer__title",children:t.title}),(0,d.jsx)("ul",{className:"footer__items clean-list",children:t.items.map(((e,t)=>(0,d.jsx)(jt,{item:e},t)))})]})}function At(e){let{columns:t}=e;return(0,d.jsx)("div",{className:"row footer__links",children:t.map(((e,t)=>(0,d.jsx)(Lt,{column:e},t)))})}function Nt(){return(0,d.jsx)("span",{className:"footer__link-separator",children:"\xb7"})}function Rt(e){let{item:t}=e;return t.html?(0,d.jsx)("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):(0,d.jsx)(Tt,{item:t})}function Pt(e){let{links:t}=e;return(0,d.jsx)("div",{className:"footer__links text--center",children:(0,d.jsx)("div",{className:"footer__links",children:t.map(((e,n)=>(0,d.jsxs)(r.Fragment,{children:[(0,d.jsx)(Rt,{item:e}),t.length!==n+1&&(0,d.jsx)(Nt,{})]},n)))})})}function Ot(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?(0,d.jsx)(At,{columns:t}):(0,d.jsx)(Pt,{links:t})}const Dt={footerLogoLink:"footerLogoLink_BH7S"};function It(e){let{logo:t}=e;const{withBaseUrl:n}=(0,se.C)(),r={light:n(t.src),dark:n(t.srcDark??t.src)};return(0,d.jsx)(pe,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:r,width:t.width,height:t.height,style:t.style})}function Ft(e){let{logo:t}=e;return t.href?(0,d.jsx)(le.Z,{href:t.href,className:Dt.footerLogoLink,target:t.target,children:(0,d.jsx)(It,{logo:t})}):(0,d.jsx)(It,{logo:t})}function Mt(e){let{copyright:t}=e;return(0,d.jsx)("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function zt(e){let{style:t,links:n,logo:r,copyright:o}=e;return(0,d.jsx)("footer",{className:(0,a.Z)("footer",{"footer--dark":"dark"===t}),children:(0,d.jsxs)("div",{className:"container container-fluid",children:[n,(r||o)&&(0,d.jsxs)("div",{className:"footer__bottom text--center",children:[r&&(0,d.jsx)("div",{className:"margin-bottom--sm",children:r}),o]})]})})}function Bt(){const{footer:e}=(0,k.L)();if(!e)return null;const{copyright:t,links:n,logo:r,style:a}=e;return(0,d.jsx)(zt,{style:a,links:n&&n.length>0&&(0,d.jsx)(Ot,{links:n}),logo:r&&(0,d.jsx)(Ft,{logo:r}),copyright:t&&(0,d.jsx)(Mt,{copyright:t})})}const $t=r.memo(Bt),Ut=(0,u.Qc)([J.S,function(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,k.L)(),t=(0,x.Z)(),[n,a]=(0,r.useState)((()=>!!t&&_()));(0,r.useEffect)((()=>{a(_())}),[]);const o=(0,r.useCallback)((()=>{T(!0),a(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=C.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;C.set(t),r&&T(!1),!r&&_()||a(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:o})),[e,n,o])}();return(0,d.jsx)(j.Provider,{value:n,children:t})},function(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return(0,d.jsx)(H.Provider,{value:n,children:t})},function(e){let{children:t}=e;return nt?(0,d.jsx)(Xe,{children:t}):(0,d.jsx)(d.Fragment,{children:t})},i.VC,function(e){let{children:t}=e;return(0,d.jsx)(I.n2,{children:(0,d.jsx)($,{children:(0,d.jsx)(Q,{children:t})})})}]);function qt(e){let{children:t}=e;return(0,d.jsx)(Ut,{children:t})}var Ht=n(2503);function Zt(e){let{error:t,tryAgain:n}=e;return(0,d.jsx)("main",{className:"container margin-vert--xl",children:(0,d.jsx)("div",{className:"row",children:(0,d.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,d.jsx)(Ht.Z,{as:"h1",className:"hero__title",children:(0,d.jsx)(s.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed",children:"This page crashed."})}),(0,d.jsx)("div",{className:"margin-vert--lg",children:(0,d.jsx)(ht,{onClick:n,className:"button button--primary shadow--lw"})}),(0,d.jsx)("hr",{}),(0,d.jsx)("div",{className:"margin-vert--md",children:(0,d.jsx)(yt,{error:t})})]})})})}const Gt={mainWrapper:"mainWrapper_z2l0"};function Vt(e){const{children:t,noFooter:n,wrapperClassName:r,title:l,description:s}=e;return(0,b.t)(),(0,d.jsxs)(qt,{children:[(0,d.jsx)(i.d,{title:l,description:s}),(0,d.jsx)(w,{}),(0,d.jsx)(D,{}),(0,d.jsx)(_t,{}),(0,d.jsx)("div",{id:p,className:(0,a.Z)(y.k.wrapper.main,Gt.mainWrapper,r),children:(0,d.jsx)(o.Z,{fallback:e=>(0,d.jsx)(Zt,{...e}),children:t})}),!n&&(0,d.jsx)($t,{})]})}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});n(7294);var r=n(5742),a=n(5893);function o(e){let{locale:t,version:n,tag:o}=e;const i=t;return(0,a.jsxs)(r.Z,{children:[t&&(0,a.jsx)("meta",{name:"docusaurus_locale",content:t}),n&&(0,a.jsx)("meta",{name:"docusaurus_version",content:n}),o&&(0,a.jsx)("meta",{name:"docusaurus_tag",content:o}),i&&(0,a.jsx)("meta",{name:"docsearch:language",content:i}),n&&(0,a.jsx)("meta",{name:"docsearch:version",content:n}),o&&(0,a.jsx)("meta",{name:"docsearch:docusaurus_tag",content:o})]})}},7186:(e,t,n)=>{"use strict";n.d(t,{z:()=>y,u:()=>s});var r=n(7294),a=n(412),o=n(469);var i=n(5893);const l="ease-in-out";function s(e){let{initialState:t}=e;const[n,a]=(0,r.useState)(t??!1),o=(0,r.useCallback)((()=>{a((e=>!e))}),[]);return{collapsed:n,setCollapsed:a,toggleCollapsed:o}}const u={display:"none",overflow:"hidden",height:"0px"},c={display:"block",overflow:"visible",height:"auto"};function d(e,t){const n=t?u:c;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function p(e){if(window.matchMedia("(prefers-reduced-motion: reduce)").matches)return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}function f(e){let{collapsibleRef:t,collapsed:n,animation:a}=e;const o=(0,r.useRef)(!1);(0,r.useEffect)((()=>{const e=t.current;function r(){const t=function(){const t=e.scrollHeight;return{transition:`height ${a?.duration??p(t)}ms ${a?.easing??l}`,height:`${t}px`}}();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return d(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(r(),requestAnimationFrame((()=>{e.style.height=u.height,e.style.overflow=u.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{r()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,a])}function m(e){if(!a.Z.canUseDOM)return e?u:c}function g(e){let{as:t="div",collapsed:n,children:a,animation:o,onCollapseTransitionEnd:l,className:s,disableSSRStyle:u}=e;const c=(0,r.useRef)(null);return f({collapsibleRef:c,collapsed:n,animation:o}),(0,i.jsx)(t,{ref:c,style:u?void 0:m(n),onTransitionEnd:e=>{"height"===e.propertyName&&(d(c.current,n),l?.(n))},className:s,children:a})}function h(e){let{collapsed:t,...n}=e;const[a,l]=(0,r.useState)(!t),[s,u]=(0,r.useState)(t);return(0,o.Z)((()=>{t||l(!0)}),[t]),(0,o.Z)((()=>{a&&u(t)}),[a,t]),a?(0,i.jsx)(g,{...n,collapsed:s}):null}function y(e){let{lazy:t,...n}=e;const r=t?h:g;return(0,i.jsx)(r,{...n})}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>y,S:()=>h});var r=n(7294),a=n(412),o=n(902),i=n(12),l=n(6668),s=n(5893);const u=r.createContext(void 0),c="theme",d=(0,i.WA)(c),p={light:"light",dark:"dark"},f=e=>e===p.dark?p.dark:p.light,m=e=>a.Z.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e),g=e=>{d.set(f(e))};function h(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.L)(),[a,o]=(0,r.useState)(m(e));(0,r.useEffect)((()=>{t&&d.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(o(t),a&&g(t)):(o(n?window.matchMedia("(prefers-color-scheme: dark)").matches?p.dark:p.light:e),d.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==c)return;const t=d.get();null!==t&&i(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:i,get isDarkTheme(){return a===p.dark},setLightTheme(){i(p.light)},setDarkTheme(){i(p.dark)}})),[a,i])}();return(0,s.jsx)(u.Provider,{value:n,children:t})}function y(){const e=(0,r.useContext)(u);if(null==e)throw new o.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>s,Zo:()=>u,n2:()=>l});var r=n(7294),a=n(902),o=n(5893);const i=r.createContext(null);function l(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return(0,o.jsx)(i.Provider,{value:n,children:t})}function s(){const e=(0,r.useContext)(i);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function u(e){let{component:t,props:n}=e;const o=(0,r.useContext)(i);if(!o)throw new a.i6("NavbarSecondaryMenuContentProvider");const[,l]=o,s=(0,a.Ql)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>a,t:()=>o});var r=n(7294);const a="navigation-with-keyboard";function o(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>l});var r=n(7294),a=n(412);const o={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function l(){const[e,t]=(0,r.useState)((()=>"ssr"));return(0,r.useEffect)((()=>{function e(){t(function(){if(!a.Z.canUseDOM)throw new Error("getWindowSize() should only be called after React hydration");return window.innerWidth>i?o.desktop:o.mobile}())}return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",unlistedBanner:"theme-unlisted-banner",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},1944:(e,t,n)=>{"use strict";n.d(t,{FG:()=>f,d:()=>d,VC:()=>m});var r=n(7294),a=n(512),o=n(5742),i=n(226);function l(){const e=r.useContext(i._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(4996),u=n(2263);var c=n(5893);function d(e){let{title:t,description:n,keywords:r,image:a,children:i}=e;const l=function(e){const{siteConfig:t}=(0,u.Z)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,s.C)(),p=a?d(a,{absolute:!0}):void 0;return(0,c.jsxs)(o.Z,{children:[t&&(0,c.jsx)("title",{children:l}),t&&(0,c.jsx)("meta",{property:"og:title",content:l}),n&&(0,c.jsx)("meta",{name:"description",content:n}),n&&(0,c.jsx)("meta",{property:"og:description",content:n}),r&&(0,c.jsx)("meta",{name:"keywords",content:Array.isArray(r)?r.join(","):r}),p&&(0,c.jsx)("meta",{property:"og:image",content:p}),p&&(0,c.jsx)("meta",{name:"twitter:image",content:p}),i]})}const p=r.createContext(void 0);function f(e){let{className:t,children:n}=e;const i=r.useContext(p),l=(0,a.Z)(i,t);return(0,c.jsxs)(p.Provider,{value:l,children:[(0,c.jsx)(o.Z,{children:(0,c.jsx)("html",{className:l})}),n]})}function m(e){let{children:t}=e;const n=l(),r=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const o=`plugin-id-${n.plugin.id}`;return(0,c.jsx)(f,{className:(0,a.Z)(r,o),children:t})}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>l,Qc:()=>c,Ql:()=>u,i6:()=>s,zX:()=>i});var r=n(7294),a=n(469),o=n(5893);function i(e){const t=(0,r.useRef)(e);return(0,a.Z)((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function l(e){const t=(0,r.useRef)();return(0,a.Z)((()=>{t.current=e})),t.current}class s extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function u(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function c(e){return t=>{let{children:n}=t;return(0,o.jsx)(o.Fragment,{children:e.reduceRight(((e,t)=>(0,o.jsx)(t,{children:e})),n)})}}},8596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>r});n(7294),n(723),n(2263);function r(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}},12:(e,t,n)=>{"use strict";n.d(t,{WA:()=>s});n(7294);const r="localStorage";function a(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(o)}function o(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,i||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),i=!0),null}var t}let i=!1;const l={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function s(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=o(t?.persistence);return null===n?l:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),a({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),a({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}},4711:(e,t,n)=>{"use strict";n.d(t,{l:()=>i});var r=n(2263),a=n(6550),o=n(8780);function i(){const{siteConfig:{baseUrl:e,url:t,trailingSlash:n},i18n:{defaultLocale:i,currentLocale:l}}=(0,r.Z)(),{pathname:s}=(0,a.TH)(),u=(0,o.applyTrailingSlash)(s,{trailingSlash:n,baseUrl:e}),c=l===i?e:e.replace(`/${l}/`,"/"),d=u.replace(e,"");return{createUrl:function(e){let{locale:n,fullyQualified:r}=e;return`${r?t:""}${function(e){return e===i?`${c}`:`${c}${e}/`}(n)}${d}`}}}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){return(0,r.Z)().siteConfig.themeConfig}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[a]=e.split(/[#?]/),o="/"===a||a===r?a:(i=a,n?function(e){return e.endsWith("/")?e:`${e}/`}(i):function(e){return e.endsWith("/")?e.slice(0,-1):e}(i));var i;return e.replace(a,o)}},4143:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var a=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}});var o=n(4143);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return o.getErrorCausalChain}})},9318:(e,t,n)=>{"use strict";n.d(t,{lX:()=>w,q_:()=>_,ob:()=>f,PP:()=>j,Ep:()=>p});var r=n(7462);function a(e){return"/"===e.charAt(0)}function o(e,t){for(var n=t,r=n+1,a=e.length;r=0;p--){var f=i[p];"."===f?o(i,p):".."===f?(o(i,p),d++):d&&(o(i,p),d--)}if(!u)for(;d--;d)i.unshift("..");!u||""===i[0]||i[0]&&a(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(8776);function s(e){return"/"===e.charAt(0)?e:"/"+e}function u(e){return"/"===e.charAt(0)?e.substr(1):e}function c(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function f(e,t,n,a){var o;"string"==typeof e?(o=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),o.state=t):(void 0===(o=(0,r.Z)({},e)).pathname&&(o.pathname=""),o.search?"?"!==o.search.charAt(0)&&(o.search="?"+o.search):o.search="",o.hash?"#"!==o.hash.charAt(0)&&(o.hash="#"+o.hash):o.hash="",void 0!==t&&void 0===o.state&&(o.state=t));try{o.pathname=decodeURI(o.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+o.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(o.key=n),a?o.pathname?"/"!==o.pathname.charAt(0)&&(o.pathname=i(o.pathname,a.pathname)):o.pathname=a.pathname:o.pathname||(o.pathname="/"),o}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof r?r(o,a):a(!0):a(!1!==o)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;rt?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,g(),w.location);c.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:v,goBack:function(){v(-1)},goForward:function(){v(1)},canGo:function(e){var t=w.index+e;return t>=0&&t{"use strict";var r=n(9864),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||a}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var u=Object.defineProperty,c=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=f(n);a&&a!==m&&e(t,a,r)}var i=c(n);d&&(i=i.concat(d(n)));for(var l=s(t),g=s(n),h=0;h{"use strict";e.exports=function(e,t,n,r,a,o,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var u=[n,r,a,o,i,l],c=0;(s=new Error(t.replace(/%s/g,(function(){return u[c++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},2497:(e,t,n)=>{"use strict";n.r(t)},2295:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
'};function a(e,t,n){return en?n:e}function o(e){return 100*(-1+e)}function i(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+o(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+o(e)+"%,0)"}:{"margin-left":o(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var o=n.render(!t),u=o.querySelector(r.barSelector),c=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(u,i(e,c,d)),1===e?(s(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){s(o,{transition:"all "+c+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),c)}),c)):setTimeout(t,c)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");c(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,i=t.querySelector(r.barSelector),l=e?"-100":o(n.status||0),u=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&f(a),u!=document.body&&c(u,"nprogress-custom-parent"),u.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,o=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+o)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function o(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&o(e,n,r);else o(e,a[1],a[2])}}();function u(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function c(e,t){var n=p(e),r=n+t;u(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);u(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},4779:(e,t,n)=>{var r=n(5826);e.exports=f,e.exports.parse=o,e.exports.compile=function(e,t){return l(o(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=p;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function o(e,t){for(var n,r=[],o=0,i=0,l="",c=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],p=n[1],f=n.index;if(l+=e.slice(i,f),i=f+d.length,p)l+=p[1];else{var m=e[i],g=n[2],h=n[3],y=n[4],b=n[5],v=n[6],w=n[7];l&&(r.push(l),l="");var k=null!=g&&null!=m&&m!==g,x="+"===v||"*"===v,S="?"===v||"*"===v,E=n[2]||c,C=y||b;r.push({name:h||o++,prefix:g||"",delimiter:E,optional:S,repeat:x,partial:k,asterisk:!!w,pattern:C?u(C):w?".*":"[^"+s(E)+"]+?"})}}return i{e.exports&&(e.exports={core:{meta:{path:"components/prism-core.js",option:"mandatory"},core:"Core"},themes:{meta:{path:"themes/{id}.css",link:"index.html?theme={id}",exclusive:!0},prism:{title:"Default",option:"default"},"prism-dark":"Dark","prism-funky":"Funky","prism-okaidia":{title:"Okaidia",owner:"ocodia"},"prism-twilight":{title:"Twilight",owner:"remybach"},"prism-coy":{title:"Coy",owner:"tshedor"},"prism-solarizedlight":{title:"Solarized Light",owner:"hectormatos2011 "},"prism-tomorrow":{title:"Tomorrow Night",owner:"Rosey"}},languages:{meta:{path:"components/prism-{id}",noCSS:!0,examplesPath:"examples/prism-{id}",addCheckAll:!0},markup:{title:"Markup",alias:["html","xml","svg","mathml","ssml","atom","rss"],aliasTitles:{html:"HTML",xml:"XML",svg:"SVG",mathml:"MathML",ssml:"SSML",atom:"Atom",rss:"RSS"},option:"default"},css:{title:"CSS",option:"default",modify:"markup"},clike:{title:"C-like",option:"default"},javascript:{title:"JavaScript",require:"clike",modify:"markup",optional:"regex",alias:"js",option:"default"},abap:{title:"ABAP",owner:"dellagustin"},abnf:{title:"ABNF",owner:"RunDevelopment"},actionscript:{title:"ActionScript",require:"javascript",modify:"markup",owner:"Golmote"},ada:{title:"Ada",owner:"Lucretia"},agda:{title:"Agda",owner:"xy-ren"},al:{title:"AL",owner:"RunDevelopment"},antlr4:{title:"ANTLR4",alias:"g4",owner:"RunDevelopment"},apacheconf:{title:"Apache Configuration",owner:"GuiTeK"},apex:{title:"Apex",require:["clike","sql"],owner:"RunDevelopment"},apl:{title:"APL",owner:"ngn"},applescript:{title:"AppleScript",owner:"Golmote"},aql:{title:"AQL",owner:"RunDevelopment"},arduino:{title:"Arduino",require:"cpp",alias:"ino",owner:"dkern"},arff:{title:"ARFF",owner:"Golmote"},armasm:{title:"ARM Assembly",alias:"arm-asm",owner:"RunDevelopment"},arturo:{title:"Arturo",alias:"art",optional:["bash","css","javascript","markup","markdown","sql"],owner:"drkameleon"},asciidoc:{alias:"adoc",title:"AsciiDoc",owner:"Golmote"},aspnet:{title:"ASP.NET (C#)",require:["markup","csharp"],owner:"nauzilus"},asm6502:{title:"6502 Assembly",owner:"kzurawel"},asmatmel:{title:"Atmel AVR Assembly",owner:"cerkit"},autohotkey:{title:"AutoHotkey",owner:"aviaryan"},autoit:{title:"AutoIt",owner:"Golmote"},avisynth:{title:"AviSynth",alias:"avs",owner:"Zinfidel"},"avro-idl":{title:"Avro IDL",alias:"avdl",owner:"RunDevelopment"},awk:{title:"AWK",alias:"gawk",aliasTitles:{gawk:"GAWK"},owner:"RunDevelopment"},bash:{title:"Bash",alias:["sh","shell"],aliasTitles:{sh:"Shell",shell:"Shell"},owner:"zeitgeist87"},basic:{title:"BASIC",owner:"Golmote"},batch:{title:"Batch",owner:"Golmote"},bbcode:{title:"BBcode",alias:"shortcode",aliasTitles:{shortcode:"Shortcode"},owner:"RunDevelopment"},bbj:{title:"BBj",owner:"hyyan"},bicep:{title:"Bicep",owner:"johnnyreilly"},birb:{title:"Birb",require:"clike",owner:"Calamity210"},bison:{title:"Bison",require:"c",owner:"Golmote"},bnf:{title:"BNF",alias:"rbnf",aliasTitles:{rbnf:"RBNF"},owner:"RunDevelopment"},bqn:{title:"BQN",owner:"yewscion"},brainfuck:{title:"Brainfuck",owner:"Golmote"},brightscript:{title:"BrightScript",owner:"RunDevelopment"},bro:{title:"Bro",owner:"wayward710"},bsl:{title:"BSL (1C:Enterprise)",alias:"oscript",aliasTitles:{oscript:"OneScript"},owner:"Diversus23"},c:{title:"C",require:"clike",owner:"zeitgeist87"},csharp:{title:"C#",require:"clike",alias:["cs","dotnet"],owner:"mvalipour"},cpp:{title:"C++",require:"c",owner:"zeitgeist87"},cfscript:{title:"CFScript",require:"clike",alias:"cfc",owner:"mjclemente"},chaiscript:{title:"ChaiScript",require:["clike","cpp"],owner:"RunDevelopment"},cil:{title:"CIL",owner:"sbrl"},cilkc:{title:"Cilk/C",require:"c",alias:"cilk-c",owner:"OpenCilk"},cilkcpp:{title:"Cilk/C++",require:"cpp",alias:["cilk-cpp","cilk"],owner:"OpenCilk"},clojure:{title:"Clojure",owner:"troglotit"},cmake:{title:"CMake",owner:"mjrogozinski"},cobol:{title:"COBOL",owner:"RunDevelopment"},coffeescript:{title:"CoffeeScript",require:"javascript",alias:"coffee",owner:"R-osey"},concurnas:{title:"Concurnas",alias:"conc",owner:"jasontatton"},csp:{title:"Content-Security-Policy",owner:"ScottHelme"},cooklang:{title:"Cooklang",owner:"ahue"},coq:{title:"Coq",owner:"RunDevelopment"},crystal:{title:"Crystal",require:"ruby",owner:"MakeNowJust"},"css-extras":{title:"CSS Extras",require:"css",modify:"css",owner:"milesj"},csv:{title:"CSV",owner:"RunDevelopment"},cue:{title:"CUE",owner:"RunDevelopment"},cypher:{title:"Cypher",owner:"RunDevelopment"},d:{title:"D",require:"clike",owner:"Golmote"},dart:{title:"Dart",require:"clike",owner:"Golmote"},dataweave:{title:"DataWeave",owner:"machaval"},dax:{title:"DAX",owner:"peterbud"},dhall:{title:"Dhall",owner:"RunDevelopment"},diff:{title:"Diff",owner:"uranusjr"},django:{title:"Django/Jinja2",require:"markup-templating",alias:"jinja2",owner:"romanvm"},"dns-zone-file":{title:"DNS zone file",owner:"RunDevelopment",alias:"dns-zone"},docker:{title:"Docker",alias:"dockerfile",owner:"JustinBeckwith"},dot:{title:"DOT (Graphviz)",alias:"gv",optional:"markup",owner:"RunDevelopment"},ebnf:{title:"EBNF",owner:"RunDevelopment"},editorconfig:{title:"EditorConfig",owner:"osipxd"},eiffel:{title:"Eiffel",owner:"Conaclos"},ejs:{title:"EJS",require:["javascript","markup-templating"],owner:"RunDevelopment",alias:"eta",aliasTitles:{eta:"Eta"}},elixir:{title:"Elixir",owner:"Golmote"},elm:{title:"Elm",owner:"zwilias"},etlua:{title:"Embedded Lua templating",require:["lua","markup-templating"],owner:"RunDevelopment"},erb:{title:"ERB",require:["ruby","markup-templating"],owner:"Golmote"},erlang:{title:"Erlang",owner:"Golmote"},"excel-formula":{title:"Excel Formula",alias:["xlsx","xls"],owner:"RunDevelopment"},fsharp:{title:"F#",require:"clike",owner:"simonreynolds7"},factor:{title:"Factor",owner:"catb0t"},false:{title:"False",owner:"edukisto"},"firestore-security-rules":{title:"Firestore security rules",require:"clike",owner:"RunDevelopment"},flow:{title:"Flow",require:"javascript",owner:"Golmote"},fortran:{title:"Fortran",owner:"Golmote"},ftl:{title:"FreeMarker Template Language",require:"markup-templating",owner:"RunDevelopment"},gml:{title:"GameMaker Language",alias:"gamemakerlanguage",require:"clike",owner:"LiarOnce"},gap:{title:"GAP (CAS)",owner:"RunDevelopment"},gcode:{title:"G-code",owner:"RunDevelopment"},gdscript:{title:"GDScript",owner:"RunDevelopment"},gedcom:{title:"GEDCOM",owner:"Golmote"},gettext:{title:"gettext",alias:"po",owner:"RunDevelopment"},gherkin:{title:"Gherkin",owner:"hason"},git:{title:"Git",owner:"lgiraudel"},glsl:{title:"GLSL",require:"c",owner:"Golmote"},gn:{title:"GN",alias:"gni",owner:"RunDevelopment"},"linker-script":{title:"GNU Linker Script",alias:"ld",owner:"RunDevelopment"},go:{title:"Go",require:"clike",owner:"arnehormann"},"go-module":{title:"Go module",alias:"go-mod",owner:"RunDevelopment"},gradle:{title:"Gradle",require:"clike",owner:"zeabdelkhalek-badido18"},graphql:{title:"GraphQL",optional:"markdown",owner:"Golmote"},groovy:{title:"Groovy",require:"clike",owner:"robfletcher"},haml:{title:"Haml",require:"ruby",optional:["css","css-extras","coffeescript","erb","javascript","less","markdown","scss","textile"],owner:"Golmote"},handlebars:{title:"Handlebars",require:"markup-templating",alias:["hbs","mustache"],aliasTitles:{mustache:"Mustache"},owner:"Golmote"},haskell:{title:"Haskell",alias:"hs",owner:"bholst"},haxe:{title:"Haxe",require:"clike",optional:"regex",owner:"Golmote"},hcl:{title:"HCL",owner:"outsideris"},hlsl:{title:"HLSL",require:"c",owner:"RunDevelopment"},hoon:{title:"Hoon",owner:"matildepark"},http:{title:"HTTP",optional:["csp","css","hpkp","hsts","javascript","json","markup","uri"],owner:"danielgtaylor"},hpkp:{title:"HTTP Public-Key-Pins",owner:"ScottHelme"},hsts:{title:"HTTP Strict-Transport-Security",owner:"ScottHelme"},ichigojam:{title:"IchigoJam",owner:"BlueCocoa"},icon:{title:"Icon",owner:"Golmote"},"icu-message-format":{title:"ICU Message Format",owner:"RunDevelopment"},idris:{title:"Idris",alias:"idr",owner:"KeenS",require:"haskell"},ignore:{title:".ignore",owner:"osipxd",alias:["gitignore","hgignore","npmignore"],aliasTitles:{gitignore:".gitignore",hgignore:".hgignore",npmignore:".npmignore"}},inform7:{title:"Inform 7",owner:"Golmote"},ini:{title:"Ini",owner:"aviaryan"},io:{title:"Io",owner:"AlesTsurko"},j:{title:"J",owner:"Golmote"},java:{title:"Java",require:"clike",owner:"sherblot"},javadoc:{title:"JavaDoc",require:["markup","java","javadoclike"],modify:"java",optional:"scala",owner:"RunDevelopment"},javadoclike:{title:"JavaDoc-like",modify:["java","javascript","php"],owner:"RunDevelopment"},javastacktrace:{title:"Java stack trace",owner:"RunDevelopment"},jexl:{title:"Jexl",owner:"czosel"},jolie:{title:"Jolie",require:"clike",owner:"thesave"},jq:{title:"JQ",owner:"RunDevelopment"},jsdoc:{title:"JSDoc",require:["javascript","javadoclike","typescript"],modify:"javascript",optional:["actionscript","coffeescript"],owner:"RunDevelopment"},"js-extras":{title:"JS Extras",require:"javascript",modify:"javascript",optional:["actionscript","coffeescript","flow","n4js","typescript"],owner:"RunDevelopment"},json:{title:"JSON",alias:"webmanifest",aliasTitles:{webmanifest:"Web App Manifest"},owner:"CupOfTea696"},json5:{title:"JSON5",require:"json",owner:"RunDevelopment"},jsonp:{title:"JSONP",require:"json",owner:"RunDevelopment"},jsstacktrace:{title:"JS stack trace",owner:"sbrl"},"js-templates":{title:"JS Templates",require:"javascript",modify:"javascript",optional:["css","css-extras","graphql","markdown","markup","sql"],owner:"RunDevelopment"},julia:{title:"Julia",owner:"cdagnino"},keepalived:{title:"Keepalived Configure",owner:"dev-itsheng"},keyman:{title:"Keyman",owner:"mcdurdin"},kotlin:{title:"Kotlin",alias:["kt","kts"],aliasTitles:{kts:"Kotlin Script"},require:"clike",owner:"Golmote"},kumir:{title:"KuMir (\u041a\u0443\u041c\u0438\u0440)",alias:"kum",owner:"edukisto"},kusto:{title:"Kusto",owner:"RunDevelopment"},latex:{title:"LaTeX",alias:["tex","context"],aliasTitles:{tex:"TeX",context:"ConTeXt"},owner:"japborst"},latte:{title:"Latte",require:["clike","markup-templating","php"],owner:"nette"},less:{title:"Less",require:"css",optional:"css-extras",owner:"Golmote"},lilypond:{title:"LilyPond",require:"scheme",alias:"ly",owner:"RunDevelopment"},liquid:{title:"Liquid",require:"markup-templating",owner:"cinhtau"},lisp:{title:"Lisp",alias:["emacs","elisp","emacs-lisp"],owner:"JuanCaicedo"},livescript:{title:"LiveScript",owner:"Golmote"},llvm:{title:"LLVM IR",owner:"porglezomp"},log:{title:"Log file",optional:"javastacktrace",owner:"RunDevelopment"},lolcode:{title:"LOLCODE",owner:"Golmote"},lua:{title:"Lua",owner:"Golmote"},magma:{title:"Magma (CAS)",owner:"RunDevelopment"},makefile:{title:"Makefile",owner:"Golmote"},markdown:{title:"Markdown",require:"markup",optional:"yaml",alias:"md",owner:"Golmote"},"markup-templating":{title:"Markup templating",require:"markup",owner:"Golmote"},mata:{title:"Mata",owner:"RunDevelopment"},matlab:{title:"MATLAB",owner:"Golmote"},maxscript:{title:"MAXScript",owner:"RunDevelopment"},mel:{title:"MEL",owner:"Golmote"},mermaid:{title:"Mermaid",owner:"RunDevelopment"},metafont:{title:"METAFONT",owner:"LaeriExNihilo"},mizar:{title:"Mizar",owner:"Golmote"},mongodb:{title:"MongoDB",owner:"airs0urce",require:"javascript"},monkey:{title:"Monkey",owner:"Golmote"},moonscript:{title:"MoonScript",alias:"moon",owner:"RunDevelopment"},n1ql:{title:"N1QL",owner:"TMWilds"},n4js:{title:"N4JS",require:"javascript",optional:"jsdoc",alias:"n4jsd",owner:"bsmith-n4"},"nand2tetris-hdl":{title:"Nand To Tetris HDL",owner:"stephanmax"},naniscript:{title:"Naninovel Script",owner:"Elringus",alias:"nani"},nasm:{title:"NASM",owner:"rbmj"},neon:{title:"NEON",owner:"nette"},nevod:{title:"Nevod",owner:"nezaboodka"},nginx:{title:"nginx",owner:"volado"},nim:{title:"Nim",owner:"Golmote"},nix:{title:"Nix",owner:"Golmote"},nsis:{title:"NSIS",owner:"idleberg"},objectivec:{title:"Objective-C",require:"c",alias:"objc",owner:"uranusjr"},ocaml:{title:"OCaml",owner:"Golmote"},odin:{title:"Odin",owner:"edukisto"},opencl:{title:"OpenCL",require:"c",modify:["c","cpp"],owner:"Milania1"},openqasm:{title:"OpenQasm",alias:"qasm",owner:"RunDevelopment"},oz:{title:"Oz",owner:"Golmote"},parigp:{title:"PARI/GP",owner:"Golmote"},parser:{title:"Parser",require:"markup",owner:"Golmote"},pascal:{title:"Pascal",alias:"objectpascal",aliasTitles:{objectpascal:"Object Pascal"},owner:"Golmote"},pascaligo:{title:"Pascaligo",owner:"DefinitelyNotAGoat"},psl:{title:"PATROL Scripting Language",owner:"bertysentry"},pcaxis:{title:"PC-Axis",alias:"px",owner:"RunDevelopment"},peoplecode:{title:"PeopleCode",alias:"pcode",owner:"RunDevelopment"},perl:{title:"Perl",owner:"Golmote"},php:{title:"PHP",require:"markup-templating",owner:"milesj"},phpdoc:{title:"PHPDoc",require:["php","javadoclike"],modify:"php",owner:"RunDevelopment"},"php-extras":{title:"PHP Extras",require:"php",modify:"php",owner:"milesj"},"plant-uml":{title:"PlantUML",alias:"plantuml",owner:"RunDevelopment"},plsql:{title:"PL/SQL",require:"sql",owner:"Golmote"},powerquery:{title:"PowerQuery",alias:["pq","mscript"],owner:"peterbud"},powershell:{title:"PowerShell",owner:"nauzilus"},processing:{title:"Processing",require:"clike",owner:"Golmote"},prolog:{title:"Prolog",owner:"Golmote"},promql:{title:"PromQL",owner:"arendjr"},properties:{title:".properties",owner:"Golmote"},protobuf:{title:"Protocol Buffers",require:"clike",owner:"just-boris"},pug:{title:"Pug",require:["markup","javascript"],optional:["coffeescript","ejs","handlebars","less","livescript","markdown","scss","stylus","twig"],owner:"Golmote"},puppet:{title:"Puppet",owner:"Golmote"},pure:{title:"Pure",optional:["c","cpp","fortran"],owner:"Golmote"},purebasic:{title:"PureBasic",require:"clike",alias:"pbfasm",owner:"HeX0R101"},purescript:{title:"PureScript",require:"haskell",alias:"purs",owner:"sriharshachilakapati"},python:{title:"Python",alias:"py",owner:"multipetros"},qsharp:{title:"Q#",require:"clike",alias:"qs",owner:"fedonman"},q:{title:"Q (kdb+ database)",owner:"Golmote"},qml:{title:"QML",require:"javascript",owner:"RunDevelopment"},qore:{title:"Qore",require:"clike",owner:"temnroegg"},r:{title:"R",owner:"Golmote"},racket:{title:"Racket",require:"scheme",alias:"rkt",owner:"RunDevelopment"},cshtml:{title:"Razor C#",alias:"razor",require:["markup","csharp"],optional:["css","css-extras","javascript","js-extras"],owner:"RunDevelopment"},jsx:{title:"React JSX",require:["markup","javascript"],optional:["jsdoc","js-extras","js-templates"],owner:"vkbansal"},tsx:{title:"React TSX",require:["jsx","typescript"]},reason:{title:"Reason",require:"clike",owner:"Golmote"},regex:{title:"Regex",owner:"RunDevelopment"},rego:{title:"Rego",owner:"JordanSh"},renpy:{title:"Ren'py",alias:"rpy",owner:"HyuchiaDiego"},rescript:{title:"ReScript",alias:"res",owner:"vmarcosp"},rest:{title:"reST (reStructuredText)",owner:"Golmote"},rip:{title:"Rip",owner:"ravinggenius"},roboconf:{title:"Roboconf",owner:"Golmote"},robotframework:{title:"Robot Framework",alias:"robot",owner:"RunDevelopment"},ruby:{title:"Ruby",require:"clike",alias:"rb",owner:"samflores"},rust:{title:"Rust",owner:"Golmote"},sas:{title:"SAS",optional:["groovy","lua","sql"],owner:"Golmote"},sass:{title:"Sass (Sass)",require:"css",optional:"css-extras",owner:"Golmote"},scss:{title:"Sass (SCSS)",require:"css",optional:"css-extras",owner:"MoOx"},scala:{title:"Scala",require:"java",owner:"jozic"},scheme:{title:"Scheme",owner:"bacchus123"},"shell-session":{title:"Shell session",require:"bash",alias:["sh-session","shellsession"],owner:"RunDevelopment"},smali:{title:"Smali",owner:"RunDevelopment"},smalltalk:{title:"Smalltalk",owner:"Golmote"},smarty:{title:"Smarty",require:"markup-templating",optional:"php",owner:"Golmote"},sml:{title:"SML",alias:"smlnj",aliasTitles:{smlnj:"SML/NJ"},owner:"RunDevelopment"},solidity:{title:"Solidity (Ethereum)",alias:"sol",require:"clike",owner:"glachaud"},"solution-file":{title:"Solution file",alias:"sln",owner:"RunDevelopment"},soy:{title:"Soy (Closure Template)",require:"markup-templating",owner:"Golmote"},sparql:{title:"SPARQL",require:"turtle",owner:"Triply-Dev",alias:"rq"},"splunk-spl":{title:"Splunk SPL",owner:"RunDevelopment"},sqf:{title:"SQF: Status Quo Function (Arma 3)",require:"clike",owner:"RunDevelopment"},sql:{title:"SQL",owner:"multipetros"},squirrel:{title:"Squirrel",require:"clike",owner:"RunDevelopment"},stan:{title:"Stan",owner:"RunDevelopment"},stata:{title:"Stata Ado",require:["mata","java","python"],owner:"RunDevelopment"},iecst:{title:"Structured Text (IEC 61131-3)",owner:"serhioromano"},stylus:{title:"Stylus",owner:"vkbansal"},supercollider:{title:"SuperCollider",alias:"sclang",owner:"RunDevelopment"},swift:{title:"Swift",owner:"chrischares"},systemd:{title:"Systemd configuration file",owner:"RunDevelopment"},"t4-templating":{title:"T4 templating",owner:"RunDevelopment"},"t4-cs":{title:"T4 Text Templates (C#)",require:["t4-templating","csharp"],alias:"t4",owner:"RunDevelopment"},"t4-vb":{title:"T4 Text Templates (VB)",require:["t4-templating","vbnet"],owner:"RunDevelopment"},tap:{title:"TAP",owner:"isaacs",require:"yaml"},tcl:{title:"Tcl",owner:"PeterChaplin"},tt2:{title:"Template Toolkit 2",require:["clike","markup-templating"],owner:"gflohr"},textile:{title:"Textile",require:"markup",optional:"css",owner:"Golmote"},toml:{title:"TOML",owner:"RunDevelopment"},tremor:{title:"Tremor",alias:["trickle","troy"],owner:"darach",aliasTitles:{trickle:"trickle",troy:"troy"}},turtle:{title:"Turtle",alias:"trig",aliasTitles:{trig:"TriG"},owner:"jakubklimek"},twig:{title:"Twig",require:"markup-templating",owner:"brandonkelly"},typescript:{title:"TypeScript",require:"javascript",optional:"js-templates",alias:"ts",owner:"vkbansal"},typoscript:{title:"TypoScript",alias:"tsconfig",aliasTitles:{tsconfig:"TSConfig"},owner:"dkern"},unrealscript:{title:"UnrealScript",alias:["uscript","uc"],owner:"RunDevelopment"},uorazor:{title:"UO Razor Script",owner:"jaseowns"},uri:{title:"URI",alias:"url",aliasTitles:{url:"URL"},owner:"RunDevelopment"},v:{title:"V",require:"clike",owner:"taggon"},vala:{title:"Vala",require:"clike",optional:"regex",owner:"TemplarVolk"},vbnet:{title:"VB.Net",require:"basic",owner:"Bigsby"},velocity:{title:"Velocity",require:"markup",owner:"Golmote"},verilog:{title:"Verilog",owner:"a-rey"},vhdl:{title:"VHDL",owner:"a-rey"},vim:{title:"vim",owner:"westonganger"},"visual-basic":{title:"Visual Basic",alias:["vb","vba"],aliasTitles:{vba:"VBA"},owner:"Golmote"},warpscript:{title:"WarpScript",owner:"RunDevelopment"},wasm:{title:"WebAssembly",owner:"Golmote"},"web-idl":{title:"Web IDL",alias:"webidl",owner:"RunDevelopment"},wgsl:{title:"WGSL",owner:"Dr4gonthree"},wiki:{title:"Wiki markup",require:"markup",owner:"Golmote"},wolfram:{title:"Wolfram language",alias:["mathematica","nb","wl"],aliasTitles:{mathematica:"Mathematica",nb:"Mathematica Notebook"},owner:"msollami"},wren:{title:"Wren",owner:"clsource"},xeora:{title:"Xeora",require:"markup",alias:"xeoracube",aliasTitles:{xeoracube:"XeoraCube"},owner:"freakmaxi"},"xml-doc":{title:"XML doc (.net)",require:"markup",modify:["csharp","fsharp","vbnet"],owner:"RunDevelopment"},xojo:{title:"Xojo (REALbasic)",owner:"Golmote"},xquery:{title:"XQuery",require:"markup",owner:"Golmote"},yaml:{title:"YAML",alias:"yml",owner:"hason"},yang:{title:"YANG",owner:"RunDevelopment"},zig:{title:"Zig",owner:"RunDevelopment"}},plugins:{meta:{path:"plugins/{id}/prism-{id}",link:"plugins/{id}/"},"line-highlight":{title:"Line Highlight",description:"Highlights specific lines and/or line ranges."},"line-numbers":{title:"Line Numbers",description:"Line number at the beginning of code lines.",owner:"kuba-kubula"},"show-invisibles":{title:"Show Invisibles",description:"Show hidden characters such as tabs and line breaks.",optional:["autolinker","data-uri-highlight"]},autolinker:{title:"Autolinker",description:"Converts URLs and emails in code to clickable links. Parses Markdown links in comments."},wpd:{title:"WebPlatform Docs",description:'Makes tokens link to WebPlatform.org documentation. The links open in a new tab.'},"custom-class":{title:"Custom Class",description:"This plugin allows you to prefix Prism's default classes (.comment can become .namespace--comment) or replace them with your defined ones (like .editor__comment). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll and highlightAllUnder methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},2885:(e,t,n)=>{const r=n(9901),a=n(9642),o=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...o,...Object.keys(Prism.languages)];a(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(6500).resolve(t)],delete Prism.languages[e],n(6500)(t),o.add(e)}))}i.silent=!1,e.exports=i},6854:()=>{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var s=0;s=o.length);s++){var u=l[s];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=o[a],d=n.tokenStack[c],p="string"==typeof u?u:u.content,f=t(r,c),m=p.indexOf(f);if(m>-1){++a;var g=p.substring(0,m),h=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),y=p.substring(m+f.length),b=[];g&&b.push.apply(b,i([g])),b.push(h),y&&b.push.apply(b,i([y])),"string"==typeof u?l.splice.apply(l,[s,1].concat(b)):u.content=b}}else u.content&&i(u.content)}return l}(n.tokens)}}}})}(Prism)},6726:(e,t,n)=>{var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6726},6500:(e,t,n)=>{var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6500},9642:e=>{"use strict";var t=function(){var e=function(){};function t(e,t){Array.isArray(e)?e.forEach(t):null!=e&&t(e,0)}function n(e){for(var t={},n=0,r=e.length;n "));var l={},s=e[r];if(s){function u(t){if(!(t in e))throw new Error(r+" depends on an unknown component "+t);if(!(t in l))for(var i in a(t,o),l[t]=!0,n[t])l[i]=!0}t(s.require,u),t(s.optional,u),t(s.modify,u)}n[r]=l,o.pop()}}return function(e){var t=n[e];return t||(a(e,r),t=n[e]),t}}function a(e){for(var t in e)return!0;return!1}return function(o,i,l){var s=function(e){var t={};for(var n in e){var r=e[n];for(var a in r)if("meta"!=a){var o=r[a];t[a]="string"==typeof o?{title:o}:o}}return t}(o),u=function(e){var n;return function(r){if(r in e)return r;if(!n)for(var a in n={},e){var o=e[a];t(o&&o.alias,(function(t){if(t in n)throw new Error(t+" cannot be alias for both "+a+" and "+n[t]);if(t in e)throw new Error(t+" cannot be alias of "+a+" because it is a component.");n[t]=a}))}return n[r]||r}}(s);i=i.map(u),l=(l||[]).map(u);var c=n(i),d=n(l);i.forEach((function e(n){var r=s[n];t(r&&r.require,(function(t){t in d||(c[t]=!0,e(t))}))}));for(var p,f=r(s),m=c;a(m);){for(var g in p={},m){var h=s[g];t(h&&h.modify,(function(e){e in d&&(p[e]=!0)}))}for(var y in d)if(!(y in c))for(var b in f(y))if(b in c){p[y]=!0;break}for(var v in m=p)c[v]=!0}var w={getIds:function(){var e=[];return w.load((function(t){e.push(t)})),e},load:function(t,n){return function(t,n,r,a){var o=a?a.series:void 0,i=a?a.parallel:e,l={},s={};function u(e){if(e in l)return l[e];s[e]=!0;var a,c=[];for(var d in t(e))d in n&&c.push(d);if(0===c.length)a=r(e);else{var p=i(c.map((function(e){var t=u(e);return delete s[e],t})));o?a=o(p,(function(){return r(e)})):r(e)}return l[e]=a}for(var c in n)u(c);var d=[];for(var p in s)d.push(l[p]);return i(d)}(f,c,t,n)}};return w}}();e.exports=t},2703:(e,t,n)=>{"use strict";var r=n(414);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),a=n(3840);function o(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n