Squashed commit of the following: commit 174b9633740ce097912af11b2f182cbe42a6c63f Author: Prithu Goswami <pg@prithu.dev> Date: Wed Nov 20 14:07:44 2024 +0530 remove console.log commit 13191636088050ab79f2f7332c8e0c14ed0bbb2c Author: Prithu Goswami <pg@prithu.dev> Date: Wed Nov 20 14:07:15 2024 +0530 add trim before query match commit 5cbbd463a728ccb4656baef70b35b89577731efe Author: Prithu Goswami <pg@prithu.dev> Date: Wed Nov 20 13:43:50 2024 +0530 more cleanup commit 53a4dbd4286d009b5f7943f0f9178429bb9fc60e Author: Prithu Goswami <pg@prithu.dev> Date: Wed Nov 20 13:42:08 2024 +0530 cleanup imba commit d6286273921f7bd18e4b374650972a1fd2326c84 Author: Prithu Goswami <pg@prithu.dev> Date: Wed Nov 20 13:37:47 2024 +0530 add regex searching commit ad0bb564a3c9963d8e3e5854d70fba4cc7890b00 Author: Prithu Goswami <pg@prithu.dev> Date: Wed Nov 20 12:23:49 2024 +0530 remove some notes and add date and tags commit 826c73cf0017f423fefd08161bfb6d7edd800e80 Author: Prithu Goswami <pg@prithu.dev> Date: Wed Nov 20 10:11:16 2024 +0530 remove global text color commit eff8d09c488fea9daf682316645273895b5dc0f8 Author: Prithu Goswami <pg@prithu.dev> Date: Wed Nov 20 10:07:51 2024 +0530 remove css from main.imba commit 45aa207c6d88fca69d62a92156630ebe717f22af Author: Prithu Goswami <pg@prithu.dev> Date: Wed Nov 20 10:04:47 2024 +0530 use theme colors in searchbar commit dcc7554784bf3c1bcfbb57aa9ded172b57a2ce39 Author: Prithu Goswami <pg@prithu.dev> Date: Mon Nov 18 23:21:16 2024 +0530 update Makefile commit 2f2ec80b43478b3ef429bdebaf393d6d2fe1a1ea Author: Prithu Goswami <pg@prithu.dev> Date: Mon Nov 18 23:13:00 2024 +0530 add imba app commit c2061ab6afec303e8fcf770fa248703875cf5efb Author: Prithu Goswami <pg@prithu.dev> Date: Mon Nov 18 18:48:17 2024 +0530 add notes list commit 4807febea0572a89b8190d426019cf566832387a Author: Prithu Goswami <pg@prithu.dev> Date: Mon Nov 18 18:46:02 2024 +0530 fix intro text commit 86e6f1e42673bfb0f4a40969763444c33a6b2d4c Author: Prithu Goswami <pg@prithu.dev> Date: Mon Nov 18 18:44:51 2024 +0530 rename config commit 2472652d048a2f97e539358e10ab3f4d05048de4 Author: Prithu Goswami <pg@prithu.dev> Date: Sun Nov 10 08:37:41 2024 +0530 add notes commit 352fb62b8e357a175c3c92491da813b21ac05447 Author: Prithu Goswami <pg@prithu.dev> Date: Sun Nov 10 08:04:35 2024 +0530 use params.author
jump to
@@ -1,2 +1,5 @@
/public/ /.hugo_build.lock + +# imba built assets +/static/assets
@@ -0,0 +1,15 @@
+SHELL=/bin/bash -o pipefail + +default: build-hugo + +build-imba: + cd imba/note-search && \ + npm install && \ + npm run build && \ + cp -r dist/assets ../../static/ && \ + ls dist/assets/*js | xargs basename | xargs -I{} sed -i s/main.*\.js/{}/ ../../layouts/notes/list.html && \ + ls dist/assets/index*.css | xargs basename | xargs -I{} sed -i s/index.*\.css/{}/ ../../layouts/notes/list.html + +build-hugo: build-imba + hugo build +
@@ -1,13 +0,0 @@
-baseURL = "https://prithu.dev/" -languageCode = "en-us" -title = "Prithu Goswami" -#ignoreFiles = [ "snippets" ] - -[author] - name = "Prithu Goswami" - email = "prithu@prithu.dev" - -[markup] - [markup.highlight] - noClasses = false -
@@ -0,0 +1,22 @@
+baseURL: "https://prithu.dev/" +languageCode: "en-us" +title: "Prithu Goswami" +#ignoreFiles = [ "snippets" ] + +params: + author: + name: "Prithu Goswami" + email: "prithu@prithu.dev" + +markup: + highlight: + noClasses: false + +outputs: + section: + - json + - html + page: + - html + - json +
@@ -1,7 +1,6 @@
--- title: "Intro" --- - Hi, I'm Prithu Goswami. I currently work as a backend engineer and am interested in \*nix, Infrastructure, Cloud-native and Security. I also enjoy reading on my free time—mostly philosophy, science, engineering,
@@ -0,0 +1,29 @@
+--- +title: physical pen testers +date: 2020-04-06T19:46:00Z +slug: physical-pen-testers +tags: +- security +- infosec +--- + +I was listening to an episode of darknet diaries and learnt that there is this +profession called a "physical penetration tester" where basically a person +works for a institution who wants to test the security of their physical infrastructure +(buildings). A client could be a bank or some other financial firm. + +The [episode][ep] interviews two such people that worked for the security firm +coalfire. They tell a story of when they were hired by the Iowa state to pen +test their courthouses. And then later while they were on their job doing the +pen testing on the building they get arrested and are prosecuted with felony +charges. This gets out of hand as there is a lot of misunderstanding between +officials, the judges, the sheriff who arrested them during the night. This goes +to show that you are just not safe no matter what you are doing. Although they +were bailed out by their company, coalfire, they will have to live the lasting +consequences of the whole ordeal. Every time they get background checked, or +every time an officer pulls them over or when they apply for a job, there will +always be the stamp of "Oh this guy was once charged for burglary", even though +those men were doing their job that night. + +[ep]: https://darknetdiaries.com/episode/59 +
@@ -0,0 +1,23 @@
+--- +title: dependency chain attack on magneto +date: 2020-04-28T14:35:00Z +slug: dependency-chain-attack-on-magneto +tags: +- security +- infosec +--- + +There are hardware skimmers that collect card data when swiped but there can +also be code written that can skim cards in an online checkout screen using +code injection techniques. There was this incident where a group of hackers got +access to a Magneto site and they modified a js library used in the checkout +page and added a skimming code that would capture the card data entered in the +forms of the page and send it to their servers. + +This also bring to attention the security vulnerabilities you get exposed to +when you use libraries and code that someone else wrote. What if the CDN you +were pulling a js library was compromised and the source code now contained +some malicious code. This was discussed in [this episode][1] of darknet diaries + +[1]: https://darknetdiaries.com/episode/52 +
@@ -0,0 +1,23 @@
+--- +title: reversing a firmware of security camera and squashfs +date: 2020-04-30T21:50:00Z +slug: reversing-a-firmware-of-security-camera-and-squashfs +tags: +- security +- reverse engineering +- firmware +--- + +I saw a [cool video][1] by ghidra ninja on yt that went over firmware reversing +for an a small security camera. He got the firmware from the site of the +manufacturer and went over binwalk and showed how there's a linux +filesystem on it in squashfs form. This was really amusing — the +fact that there is a whole file system in a single binary. He then goes on +to to see a rc script that runs on the device (this is after separating the +filesystem and unsquashing it) and edits that code to include a reverse +shell using nc. Some version of nc do not have the `-e` flag though and there's a +workaround for that in the man page of nc itself. I find that kind of +ironic. + +[1]: https://youtu.be/hV8W4o-Mu2o +
@@ -0,0 +1,20 @@
+--- +title: python one-liners using list composoition +date: 2020-05-13T11:34:00Z +slug: python-one-liners-using-list-composoition +tags: +- python +- unix +--- + +TIL that there are really good ways of writing one-liners in python. I knew +they existed but today I took a closer look at them. Most of the iterations can +be done using list composition. You don't even have to be composing a list, +you could be just executing a normal function call like in the example below +uses "print" + +``` +curl -s https://www.imdb.com/list/ls020046354/export |\ + python -c 'import csv,sys;[print (a["Genres"]) for a in csv.DictReader(sys.stdin)]' +``` +
@@ -0,0 +1,16 @@
+--- +title: keeping it simple dense and precise +date: 2022-04-25T23:08:00Z +slug: keeping-it-simple-dense-and-precise +tags: +- meta +- zet +--- + +I am going to try to keep this as dense and precise as possible and only store +"usefull" knowledge. I am going keep this for things like "how was I supposed +to run a webdav server using rclone again"; well maybe not that, because that's +just a one line and belongs in the snippets.md file. But more like "how do I +setup weechat on android using an ssh tunnel and a weechat relay?". I can +imagine forgetting that. Or perhaps some sort of small tutorial or something? +
@@ -0,0 +1,96 @@
+--- +title: nginx reverse proxy and url rewrite +date: 2022-04-26T21:21:00Z +slug: nginx-reverse-proxy-and-url-rewrite +tags: +- nginx +--- + +Was just setting up [shiori][1] behind nginx and I wanted it such that +https://prithu.dev/shiori passess the request to port 8001. I have been in this +situation before as well where a path needs to be sent to a another host or application server. + +Just doing the following wont work: + +```nginx +location /app { + proxy_pass http://localhost:8001; + proxy_set_header Host $host; +} +``` + +nginx forwards the client request (`http://root.com/app`) to our app server +(assuming running locally) as `http://localhost:8001/app`, but there is no +route defined as `/app`. Our app expects a request to be sent to `/`. And this +app might just be an api. So the client making a request like +`http://root.com/app/users` would be recieved by the app server as +`http://127.0.0.1/app/users` instead of `http://127.0.0.1/users`. There are two +ways to solve this, though both of the methods are not exactly equivalent, and +other use cases and situations might warrant the use of either of them: + +1. Rewrite the URI in nginx +2. Host the app server on `/app` instead of `/` + +#### Rewriting URI on nginx + +```nginx +location /app { + rewrite /foo/(.*) /$1 break; + proxy_pass http://localhost:3200; + proxy_redirect off; + proxy_set_header Host $host; +} +``` + +nginx would then send the request to our app server as `http://localhost:8001/`. +So `http://root.com/app/users` would then be `http://127.0.0.1/users` which is +what we want. + +**Explaination**: [rewrite][2] directive takes in a regex and replaces it with the +next argument - that is the final URI that will be passed to the app server. +`$1` is the regex capture group refering to `(.*)` + +**Before rewrite**: + +```mermaid +graph LR + A[client] -->|http://root.com/app| B[nginx] + B -.http://localhost:8001/app.-> C[app server] + C -. response .-> B + B --response--> A +``` + +**After rewrite**: + +```mermaid +graph LR + A[client] -->|http://root.com/app| B[nginx] + B -.http://localhost:8001.-> C[app server] + C -. response .-> B + B --response--> A + +``` + +#### Host the app server on `/app` instead of `/` + +...Or in other words, let the app server know that the root is `/app/` and not `/` + +Most web frameworks have an option for this. `APP_ROOT="/app/"`in the +corresponding framework's equivalent should do the trick. This is what I did for shiori. +Its `serve` command has a `-r` flag that sets the root. + +Method 1. is still usefull when the app is somewhat stateless (not the correct +way of using "stateless", but yeah) - i.e it doesn't care where the root is - +it just has to respond to the request and the response is context independent +i.e it doesn't have to refer back to the host - which is mostly the case with +an api. But a webapp where the frontend and backend are closely tied, the app +needs to know what the host is. + +**More** + +[A good write up about rewrite URI][3] + +[1]: https://github.com/go-shiori/shiori +[2]: http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite +[3]: https://medium.com/rahasak/nginx-reverse-proxy-with-url-rewrite-a3361a35623c +
@@ -0,0 +1,15 @@
+--- +title: resources to learn about aws vpc +date: 2022-04-27T20:25:00Z +slug: resources-to-learn-about-aws-vpc +tags: +- aws +- resources +--- + +**Videos** + +- [Exploring the Fundamentals of AWS Networking (SVC211)](https://www.youtube.com/watch?v=8toveAOL5eA) +- [AWS Networking Fundamentals](https://www.youtube.com/watch?v=hiKPPy584Mg) +- [Working with AWS Networking and Amazon VPC](https://www.youtube.com/watch?v=rg2BTWVCQlY) +
@@ -0,0 +1,38 @@
+--- +title: setting up cgit with nginx +date: 2022-04-28T00:27:00Z +slug: setting-up-cgit-with-nginx +tags: +- nginx +- linux +--- + +```nginx +server { + server_name git.prithu.dev; + listen 80; + access_log /var/log/nginx/git.prithu.dev/access.log; + error_log /var/log/nginx/git.prithu.dev/error.log; + #auth_basic "Git Login"; + #auth_basic_user_file "/srv/git/.htpasswd"; + + location /static { + alias /var/www/cgit; + try_files $uri =404; + } + + location / { + fastcgi_pass unix:/run/fcgiwrap.socket; + fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; + fastcgi_param PATH_INFO $uri; + fastcgi_param QUERY_STRING $args; + } + + listen 443 ssl; # managed by Certbot + ssl_certificate /etc/letsencrypt/live/git.prithu.dev/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/git.prithu.dev/privkey.pem; # managed by Certbot + include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot +} +``` +
@@ -0,0 +1,13 @@
+--- +title: 'TIL: literal ipv6 in URLs' +date: 2022-04-28T01:14:00Z +slug: literal-ipv6-in-urls +tags: +- networking +- TIL +--- + +TIL from [RFC2732](https://www.ietf.org/rfc/rfc2732.txt) that the way you +access an ipv6 address in a browser is by enclosing it in square brackets +`http://[2401:4900:f00b:dead:2f2d:48ac:9fdb:b7ff]:8080/path/file.txt` +
@@ -0,0 +1,22 @@
+--- +title: playwright is really good for browser automation +date: 2022-05-01T01:31:00Z +slug: playwright-is-really-good-for-browser-automation +tags: +- automation +- webdev +--- + +[playwright](https://playwright.dev/docs/intro) is really good for browser +automation. It is a re-write of puppeteer, I believe, and is maintained by the +same devs and has tons of improvements, maybe because it was +supported/sponsored by microsoft. + +It also has a wonderful feature of automatically recording your actions and +converting them to a script. Running this would open a browser window and you +can then record your actions. + +```shell +npx playwright codegen https://netbanking.hdfcbank.com/netbanking/ +``` +
@@ -0,0 +1,26 @@
+--- +title: using xxd to create binary data +date: 2022-05-03T15:11:00Z +slug: using-xxd-to-create-binary-data +tags: +- cli +- unix +--- + +`xxd` is a great tool. I have seen it be use in so many places. For some weird +reason though it seems to come packaged with `vim`?. Don't know about other +distros, but that's the case with Arch. Seems like `xxd` was created by Bram +and is a part of vim source code. Haven't looked into it further, but that's +what I concluded. + +Anyways here's a small example: + +```sh +echo -en "89504e470d0a1a0a0000000d4948445200000001000000010100000000376ef9240000000a4944415478016360000000020001737501180000000049454e44ae426082" | xxd -r -p +``` + +The `-r` does the reverse of what xxd is meant to normally do, i.e +print hexdump of a binary data. The `-p` just tells it to treat the input as +'plain hexdump' (which is a single line of hex digits without any other +formatting) +
@@ -0,0 +1,19 @@
+--- +title: EKS vs ECS vs Fargate +date: 2022-06-07T22:02:00Z +slug: eks-vs-ecs-vs-fargate +tags: +- aws +- cloud native +- containers +--- + +tldr; ECS is just AWS's proprietary orchestration solution. EKS is their kubernetes +service - you don't have to manage the kubernetes control plane (don't have +access to master node, but you do get the kubernetes API). Fargate can be used +with ECS or EKS and basically abstracts away the compute nodes on which +containers run. + +- https://cast.ai/blog/aws-eks-vs-ecs-vs-fargate-where-to-manage-your-kubernetes +- https://aws.amazon.com/blogs/containers/the-role-of-aws-fargate-in-the-container-world +
@@ -0,0 +1,25 @@
+--- +title: AWS Resource policies +date: 2022-07-09T15:20:00Z +slug: aws-resource-policies +tags: +- aws +--- + +- There are two ways to manage access of a bucket - user policies or resources + policies. Access policies that you attach to your resources (buckets and + objects) are referred to as resource-based policies. You can also attach + polcies to your users in your account, called user policies. +- Resources policies are attached to the resource (in s3 for eg. buckets or + even objects). Resource policy dictates who is allowed to access the resource + +## Principals + +`Principal` element is used in resource-based policies. The Principal element +specifies the user, account, service, or other entity that is allowed or denied +access to a resource. + + +## Read more +- https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html +
@@ -0,0 +1,54 @@
+--- +title: AWS S3 access policy nuances +date: 2022-07-09T19:17:00Z +slug: aws-s3-access-policy-nuances +tags: +- aws +--- + +If you want to give access to everything in the bucket (objects) make sure the +resource arn for the s3 bucket must also have a `/*` indicating all objects in the bucket + +``` +"Resource": [ + "arn:aws:s3:::BUCKET-NAME", +] +``` +This one won't give access to objects in the bucket, the following one will. + +``` +"Resource": [ + "arn:aws:s3:::BUCKET-NAME", + "arn:aws:s3:::BUCKET-NAME/*" +] +``` + +- There is a difference between these two resources. One is the bucket + itself (`arn:aws:s3:::BUCKET-NAME`) and tthe other refers to the objects in + the bucket `arn:aws:s3:::BUCKET-NAME/*` +- `ListObjects` API requires `s3:ListBucket` permission ***on*** the + bucket. [^1] +- Another thing to keep in mind is that only if you have `s3:ListBucket` + permission on the bucket then you get a 404 otherwise you get a 403, which + makes sense, since you are not allowed to list the contents of a bucket, but + only access them via the key. + + From the [docs](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) + + > Permissions + > + > You need the relevant read object (or version) permission for this operation. + > For more information, see Specifying Permissions in a Policy. If the object + > that you request doesn’t exist, the error that Amazon S3 returns depends on + > whether you also have the s3:ListBucket permission. + > + > If you have the s3:ListBucket permission on the bucket, Amazon S3 returns an + > HTTP status code 404 (Not Found) error. + > + > If you don’t have the s3:ListBucket permission, Amazon S3 returns an HTTP + > status code 403 ("access denied") error. + +### Read More +- [AccessDenied for ListObjects for S3 bucket when permissions are s3:\*](https://stackoverflow.com/questions/38774798/accessdenied-for-listobjects-for-s3-bucket-when-permissions-are-s3) + +[^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html
@@ -0,0 +1,69 @@
+--- +title: Freedom of Monetary Transaction +date: 2022-07-19T19:59:00Z +slug: freedom-of-monetary-transaction +tags: +- bitcoin +- freedom +- blog +--- + + +Wrote the following in the FOSS United Telegram group, might expand this later +as a blog post. + +{{< aside >}} +#### Context +Razorpay was put under scrutiny for accepting donation for +a news org (altnews I believe?) from foreign sources. The discussion in the group was +that whether or not it should have been allowed. I just chipped in. +{{< /aside >}} + +But, is it right to curb the inflow of money from foreign sources in some cases +but allow it for others? Money should be free and neutral. It's a tool for +humans to use to communicate value, just like how data is used to communicate +information. If you believe humans should be free to communicate privately with +whomever they wish to, for any reason whatsoever, be it illegal or legal +(remember again, you can't be selective, either everyone has encrypted p2p +private communication or no one does), then why curb money? This goes with FOSS +as well, you should be free to use any software out there for whatever you want +-- only you will be liable for how you use it; the software itself doesn't care +and need not know what you are using it for. One could sell illicit goods using +magento and tor - none of those two pieces of software care about it, they are +neutral to the use case. If you believe the government has no business looking +into our chats then I fail to understand why most people here don't mind the +government having a tab on our financial activities. Richard Stallman himself +doesn't use a credit card nor does he have a bank account (might have one for +official use, cause he has no option), he likes cash, cause it's private. Also, +I am not a fan of today's "crypto", "web3" ecosystem either, most of it is just +ponzi and get rich quick schemes. Don't bash me for "supporting" it. + +Reply to the above message by a member: + +> I'm against exploring these +> questions. But as an organization working against the establishment for a +> clearly defined goals, you need to define your boundaries and working within +> the constraints imposed by the law. Otherwise you may spread yourself too +> thin fighting too many battles at the same time. + +My reply: + +And I feel more people should explore these questions and ask it from a +perspective of fundamentals and freedom and have healthy discussions around it +instead of engaging in flame wars and relentlessly bashing "crypto" for this +and that. Remember that there is a core of truth in every economic bubble. For +the CIA, Snowden is a traitor and should be put behind bars, but, for freedom +activists, hackers and other tech people, he is a hero. Those boundaries that +you say should be defined start getting very blurry when the state becomes +overbearing on it's citizens; you need to keep them in check. Today they may +stop foreign payments to some organizations tomorrow they might even ban +domestic payments or a whole organization itself from transacting, and it +doesn't take a long time for certain ideologies and emotions to take over the +decisions of a state. But, the citizens must also be wary of the law and be +persecuted if they are found to engage in unlawful conducts, it's a balancing +act, and money and data (speech) are just tools for the conduct. Might as well +add "Freedom of Monetary Transaction" in the list of rights? no? + + +Kailash Nadh himself reacted with a "like" (thumbs up emoji) on the above message. +
@@ -0,0 +1,957 @@
+--- +title: the go programming language book notes +date: 2022-08-04T20:26:00Z +slug: learning-golang +tags: +- golang +--- + +{{< aside >}} +These are notes that I took while reading the [The Go Prgogramming Language book](https://www.gopl.io/) +{{< /aside >}} + + +### Interesting points + +- Go has some strictness when it comes to compiling + - if packages are imported but not used - don't compile + - if a newline is placed incorrectly - don't compile. Newlines follwing certain tokens are converted to semicolons automatically + - Semicolons are used only when statements are to be written in one line one after another. + - if local variables are not used - don't compile +- Go also has strict code formatting rules built-in, which makes it standard everywhere. + - eg. opening brace `{` of the function must be on the same line as the declartion `func` + - In `x+y`, a newline is permitted after but not before the `+` operator +- Variables if not initialized with a value, get assigned a *zero value*. For numeric type it's 0 for strings it's "" + + +- Map is a reference to the data structure created by `make`. `c := make(map[string]int)` + + + +### Declarations + +- Case matters when declaring stuff outside a function (package-level). If upper case then the thing is "exported" and available outisde the package as well +- Four types of declartions: + - `var`, `const`, `type` and `func` +- File Sturcture +``` +<package declaration> + +<imports> + +<package-level declartions of types, variables, constants and functions> +``` +- **Variables** + - `var` _name_ _type_ = _expression_ + - Either _type_ or _= expression_ can be omitted, but not both + - `var i = "hello"` - determined by the right side expression + - Variables declared always take a default meaningful value (_zero value_) to avoid unexpected behaviour + - `0` for numbers + - `false` for booleans + - `nil` for interfaces and reference types like slice, pointer, map, channel, function + - `var i, j, k int // 0, 0, 0` + - `var b, f, s = true, 2.3, "four"` +- only withing a function, a *short variable declaration* may be used to initialize and declare a local variable + - `name := expression` - type of `name` is determined by `expression` + - Remember `:=` is a declartion and `=` is an assignment + - if some of the variables on the left-hand side of `:=` are already declared then it acts like an assignment + - A short variable declartion must declare at least one new variable + - not valid code: + ``` + f, err := os.Open(file) + f, err := oss.Create(ofile) // compile error: no new variables + ``` +- **The `new` Function** + - `new(T)` creates an unnamed variable of type `T` initializes it with the zero value of T and returns its address, which is of type `*T` + ``` + p := new(int) // p, of type *int, points to an unnamed int variable + fmt.Println(*p) // "0" + *p=2 // sets the unnamed int to 2 + fmt.Println(*p) // "2" + ``` +- Keeping a note of how garbage collection works is usefull when optimizing performance. When a pointer lives outside a scope and can reference an object + inside the scope, it still can be reached, hence the garbage collector cannot reclaim the memory allocated for the variable inside the scope. + It's good to keep in mind for performance critical programs how the garbage collection works. + +- **Scope** + - important to read **2.7. Scope** of the go book p.48, last para, till the end. + + +### Basic Types +- **Numeric Types** + - `int` is either 32 or 64 bit in width depending on the compiler + - `rune` is synonym for `int32` and indicates that the value is a Unicode code point + - `byte` is synonym for `uint8` + - `int` is not as same as `int32` even if it's natural size is 32 bits. An explicit conversion is required where 32 bits int is required + - `uintptr` enough to hold all the bits of a pointer value +- **Operators** + - ^ is bitwise XOR when it's used as a binary operator and when used as unary operator (as prefix) it is a bitwise negation or complement + - &^ operator is bit clear operator (AND NOT, i.e x ∧ ¬Y) + +#### Side note (Sets in Binary representation) +- Binary representation of a number can be thought of like a set, where 1 means that the number is in the set. And bitwise + operations will then correspond to some set operations + eg: + ```golang + var x unint8 = 1<<1 | 1<<5 + var y unint8 = 1<<1 | 1<<2 + + fmt.Println("%08b\n", x) // "00100010", the set {1, 5} + fmt.Println("%08b\n", y) // "00000110", the set {1, 2} + + fmt.Println("%08b\n", x&y) // "00000010", the intersection {1} + fmt.Println("%08b\n", x|y) // "00100110", the union {1, 2, 5} + fmt.Println("%08b\n", x^y) // "00100100", the symmetric difference {2, 5} + fmt.Println("%08b\n", x&^y) // "00100000", the difference {5} + + for i := unint(0); i < 8; i++ { + if x&(1<<i) != 0 { + fmt.Println(i) // "1", "5" + } + } + fmt.Println("%08b\n", x<<1) // "01000100", the set {2, 6} + fmt.Println("%08b\n", x>>1) // "00010001", the set {0, 4} + ``` +- **Strings** + - Strings are immutable. Which means it is safe for two copies of a string to share the same underlying memory; Substring of a string can use the same underlying memory + ![](./img/202208042026-1.png) + - Double quoted strings can have excape sequences. Including `\xhh`, `\ooo` -- where ooo is octal digits and max being `\377`, both denoting single byte with the specified value. + - Raw string literal is written with \`...\` (backticks) +- **Unicdoe** + - A unicode code point is called a rune in go terminology and is synonym to int32. UTF-32 encoding each code point has the same size 32 bits. + - In a string literal \uhhhh can be used for 16 bit value of the code point and \Uhhhhhhhh can be used for 32 bit value of the code point. Unicode escapes can also be used in rune literals `'\u4e16'` + - These are the same (underlying bytes are the same): + ``` + "世界" + "\xe4\xb8\x96\xe7\x95\x8c" + "\u4e16\u754c" + "\U00004e16\U0000754c" + ``` + - When decoding strings using utf8.DecodeRuneInString or using range and an invalid byte sequence is encountered, it is replaced with \uFFFD (white question mark) + - A []rune conversion applied to a UTF-8-encoded string returns the sequence of Unicde code points that the string encodes: + ``` + s := "プログラム" + fmt.Printf("% x\n", s) // "e3 83 97 e3 83 ad e3 82 b0 e3 83 a9 e3 83 a0" + r := []rune(s) + fmt.Printf("%x\n", r) // "[30d7 30ed 30b0 30e9 30e0]" + fmt.Println(string(r)) // プログラム + ``` +- **Constants** + - It is known that constants are evalutated at compile time. Also, since their value is known at compile time, the results of all arithmetic, logical and comparison operations applied to constant operands are themselves constants, as are the results of conversions and calls to certain built in functions such as len, cap, real, imag, complex and unsafe.Sizeof + - **iota** + - It's a constant generator. It's value begins at zero and increments by one for each item in the sequence + - Example from time package + ```golang + type Weekday int + const ( + Sunday Weekday = iota + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + ) + ``` + - Example defining constants with bits and using them + ```golang + type Flags uint + const ( + FlagUp Flags = 1 << iota + FlagBroadcast + FlagLoopback + FlagPointToPoint + FlagMulticast + ) + + func IsUp(v Flags) bool { return v&FlagUp == FlagUp } + func TurnDown(v *Flags) { *v &^= FlagUp } + func SetBroadcast(v *Flags) { *v |= FlagBroadcast } + func IsCast(v Flags) bool { return v&(FlagBroadcast|FlagMulticast) != 0 } + + func main() { + var v Flags = FlagMulticast | FlagUp + fmt.Printf("%b %t\n", v, IsUp(v)) // "10001 true" + TurnDown(&v) + fmt.Printf("%b %t\n", v, IsUp(v)) // "10000 false" + SetBroadcast(&v) + fmt.Printf("%b %t\n", v, IsUp(v)) // "10010 false" + fmt.Printf("%b %t\n", v, IsCast(v)) // "10010 true" + } + ``` + - Example of using iota to define names of powers of 1024 + ```golang + const ( + _ = 1 << (10 * iota) + KiB // 1024 + MiB // 1048576 + GiB // 1073741824 + TiB // 1099511627776 + PiB // 1125899906842624 + EiB // 1152921504606846976 + ZiB // 1180591620717411303424 + YiB // 1208925819614629174706176 + ) + ``` + - **untyped constants** + - untyped constants allows the constant to be used in expressions without worrying about the precision. untyped constants can be very big, the book says you may assume *atleast* 256 bits of precision + - only constants are untyped and are of 6 flavors: + 1. untyped boolean + 2. untyped integer + 3. untyped rune + 4. untyped floating-point + 5. untyped complex + 6. untyped string + - When untyped constants are assigend to a variable, the constant is implicitly converted to the type of that variable + - read section 3.6.2 for more + +### Composite Types +- **Arrays** + - fixed length sequence. The size is a part of it's type: + ```golang + q := [...]int{1, 2, 3} + fmt.Printf("%T\n", q) // "[3]int" + ``` + `...` means that the size must be determined by the initializing values. Else you do it like `var q [3]int = [3]int{1, 2, 3}` + - It is also possible to specify a list of index and value pairs like follows: + ```golang + type Currency int + const ( + USD Currency = iota + EUR + GBP + RMB + ) + symbol := [...]string{USD: "$", EUR: "9", GBP: "!", RMB: """} + fmt.Println(RMB, symbol[RMB]) // "3 "" + ``` + In this form, indices can appear in any order and some may be omitted; as before, unspecified + values take on the zero value for the element type. For instance, + ```golang + r := [...]int{99: -1} + ``` + defines an array r with 100 elements, all zero except for the last, which has value −1. + - We can use the `==` to check if all elements of two arrays are equal, but both the array types must be the same (also same size, since size is part of the type) +- **Slices** + - slices are variable-length sequences. It's closely connected to array and array is it's underlying data structure. + - declare and initialize a slice: + ```golang + mySlice := []string{"One", Two, Three} + ``` + - It's a lightweight data structure consisting of a `pointer` that points to the first element of an array (might not be the first element of the actual underlying array), a `length` which is the number of elements in the slice and `capacity` which is the number of elements between the start of the slice and the end of the underlying array. Built-in functions `len` and `cap` return those values + - We can't use `==` to compare two slices. But we can compare two byte slices using `bytes.Equal` function. For other types of slices, we need to do the comparison ourselves + - zero value of a slice is `nil` + - The built-in function make creates a slice of a specified element type, length, and capacity. The capacity argument may be omitted, in which case the capacity equals the length. + ```golang + make([]T, len) + make([]T, len, cap) // same as make([]T, cap)[:len] + ``` + Under the hood, `make` creates an unnamed array variable and returns a slice of it; the array is accessible only through the returned slice. In the first form, the slice is a view of the entire array. In the second, the slice is a view of only the array’s first len elements, but its capacity includes the entire array. The additional elements are set aside for future growth. + - Slices are more akin to a struct like so: + ```golang + type IntSlice struct { + ptr *int + len, cap int + } + ``` + and when you pass a slice, you are passing a copy of this slice data-structure. Ofcourse you have access to the underlying array structure which is always a reference (pointer to its location) + - `append` function + - built-in append can append items or even slices to an existing slice + ```golang + var x []int + x = append(x, 1) + x = append(x, 2, 3) + x = append(x, 4, 5, 6) + x = append(x, x...) // append the slice x + fmt.Println(x) // "[1 2 3 4 5 6 1 2 3 4 5 6]" + ``` + - we can use a slice as a stack + ```golang + stack = append(stack, v) + top := stack[len(stack)-1] + stack = stack[:len(stack)-1] + ``` + - thing to remember about slice is that it's a lightweight data-structure which only keeps track of the it's length, the capacity of it's underlying array and a pointer to that array. And when you use the slice operators (eg slice[:len(slice)-1], etc) you are creating a new slice, which points to the same array. And hence if you do change the underlying array, this reflected on both the slices. +- **Maps** + - collection of unordered key/value pairs. the map type is written as `map[K]V`. Where `K` are the types of its keys and values. All keys are of the same type and all the values are of the same type. The key type `K` must be comparable using `==` + - built in `make` can be used to create a map: + ```golang + ages := make(map[string]int) + ``` + - map literal can also be used: + ```golang + ages := map[string]int{ + "alice": 31, + "charlie" 34, + } + emptymap := map[string]int{} // initialize an emtpy map + ``` + - map elements can be deleted: + ```golang + delete(ages, "alice) + ``` + - Even if key is not present it will not throw an error and if you try to do a map lookup using a key that isn't present, it returns the zero type for its type + ```golang + age := ages["bob"] // 0 + ``` + - but if we would like to know whether the key was there or not we can do: + ```golang + age, ok := ages["bob"] + if !ok { /* "bob" was not a key in the map. do something */} + + if age, ok := ages["bob"]; !ok { /* ... */ } // shorter way of writing + ``` + - Map elements cannot be addressed. i.e you can't get their address/pointer + - Never treat map as ordered. If some sort of ordering is required, then we need to sort keys separately and then access the map: + ```golang + import "sort" + + var names []string + for name := range names{ + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + fmt.Printf("%s %d\n", name, ages[name]) + } + ``` + - map can be `nil` (it is its zero value), i.e there is no reference to a hash table anywhere. Accessing map that is nil causes panic + - like slices, maps can't be compared using `==`; will need to write a function for it. + - map can serve the purpose of a set, since keys cannot repeat + - if you do want to use slices as keys then we can convert them to say string type representation and then use it. Apparently that's a valid thing to do and the author showed an example with slices of string themselves and a function k that maps from a slice to another comparable type (in this case string) like int, bool, string, etc. so that it can be then used as a key of the map + - The value type of map can itself be a composite type, such as a map or a slice. + +- **Structs** + - structs are simply a collection of types that together form a single entity. + - Classical example: + ```golang + type Employee struct { + ID int + Name string + Address string + DoB time.Time + Position string + Salary int + ManagerID int + } + + var dilbert Employee + ``` + - You can use dot operator as usual to access the fields. Even if you have the pointer to Employee, you can use the dot operator as usual + - Field order is significant to type identity. i.e you can't change the order of declaration of the struct and expect it to be the same struct + - Struct literals: + ```golang + type Point struct{ X, Y int} + p := Point{1, 2} + ``` + - If all fields of a struct are comparable then the struct itself is comparable. The `==` operation compares the corresponding fields of the two structs in order. The two expressions printed below are equivalent: + ```golang + type Point struct{ X, Y int } + + p := Point{1, 2} + q := Point{2, 1} + fmt.Println(p.X == q.X && p.Y == q.Y) // false + fmt.Println(p == q) // false + ``` + - *Struct Embedding* + - Go lets us declare field with a type but no name, called *anonymous fields*. The type of the field must be a named type or a pointer to a named type. + - Embedding a struct refers to including a struct in the definition of a struct and making it an anonymous field. + - An example of how it is useful. + ```golang + type Point struct{ + X, Y int + } + + type Circle struct{ + Center Point + Radius int + } + + type Wheel struct{ + Circle Circle + Spokes int // number of spokes count + } + + var w Wheel w.Circle.Center.X = 8 w.Circle.Center.Y = 8 + w.Circle.Radius = 4 + w.Spokes = 24 + ``` + as you can see it's quite verbose having to mention each field and subfield. We can instead use anonymous fields like so: + ```golang + type Point struct{ + X, Y int + } + + type Circle struct{ + Point + Radius int + } + + type Wheel struct{ + Circle + Spokes int // number of spokes count + } + + var w Wheel + w.X = 8 //equivalent to w.Circle.Point.X = 8 + w.Y = 8 //equivalent to w.Circle.Point.Y = 8 + w.Radius = 4 //equivalent to w.Cirlce.Radius = 4 + w.Spokes = 24 + ``` + Note that the commented equivalent are still valid. + Struct literals will still have to mention the field types. Any of the two forms is valid: + ```golang + w = Wheel{Cirlce{Point{8, 8}, 5}, 20} + + w = Wheel{ + Circle: Circle{ + Point: Point{X: 8, Y: 8} + Radius: 5, + }, + Spokes: 20, + } + + ``` + +### 5.3 +- bare return is a shorthand way to return each of the named result variables in order + ```golang + func CountWords(url string) (words, images int, err error){ + resp, err := http.Get(url) + if err != nil { + return + } + } + + ``` + `return` above is equivlant to `return words, images, err` and the values of `words` `images` is the default values of the data type. Bare returns should be used sparingly because it isn't instantly obvious what is being returned. On the other hand it reduces verbosity and code reuse. + + +### 5.4 Errors +- If an error has only one possible cause, the result is a boolean, usually called ok +- `error` is an interface type and an error implies something went wrong and we can get its message by calling its `Error()` method or by printing it `fmt.Println(err)` `fmt.Printf("%v", err)` +- **[My note]** Go's approach with errors is that things can go wrong and programs and libraries should be well written and document what they expect can go wrong. Other than that, "exceptions" are a sort of supported (more on this when I have read it fully), they aren't the primary way of conveying that something can go wrong. First its `error` for "expected" failure and then there are "exceptions" for truly unexpected errors that indicate a bug. With if else, return control flow, go wants programmers to pay more and effor to attention to what could go wrong. + +#### 5.4.1 Five ways to handle errors: +- **[Refer Read]** 5.4.1 Error-Handling Strategies + 1. Propogate upwards and also add information and context to the error message using `fmt.Errorf()` + Be concise and precise. if `f(x)` encounters error than its + responsibility is to report attempted operation `f` and the arguments + `x` as they relate to the error. And errors can be chainged by adding to + fmt.Errorf(). From function `abc(y)`, If you want to report an error but + it happend due to another function and you want to propogate it, don't + just send it off, add more info. - `fmt.Errorf(tried doing xyz on %s: + %v, y, err)` where err is the error you got from from xyz function, + because what `xyz`'s err reported, might not make sense to the function + `abc`'s caller. + 2. Second handlin erros that represent transient problems which are un predictable, with retries-for example retyring an ht tp connection (read example in the section) + 3. Print error and stop the program gracefully, but this is mostly reserved for the main function to do. + `log.Fatalf("oh oh %v", err)` is a way to print a fatal log + 4. Some cases it's enough to log the error and continue (perhaps with less functionality) using `fmt.Fprintf(os.Stderr, "") ` or `log.Printf()` + 5. Most rarely it is okay to ignore a error and move on, but if you do, document the intention clearly + + +#### 5.7 Variadic Functions + +``` golang + func sum(vals ...int) int{ + total := 0 + for _,val := range vals{ + total += val + } + return total + } + + fmt.Println(sum(1, 2, 3, 4)) + // implicitly makes a slice of the the size of arguments passed. + + // shows how to invoke variadic function when args are already in a slice + values := []int{1, 2, 3, 4} + fmt.Println(sum(values...)) + + + // these are not the same types even though the `...int` parameter behaves lika slice within the function body + func f(...int) {} + func g([]int) {} +``` +#### 5,8 Deffered function calls +- `defer` prefix before a function call causes the function to be *called* just before the function done with its execution whether it returns, abnormally stops or panics. It is usually written just after acquiring a resource. +- A nice trick to pair "on-entry" and "on-exit" actions using defer + ```golang + func bigSlowOperation(){ + defer trace("bigSlowOperation")() + // ... work + time.Sleep(10 * time.Second) + } + + func trace(msg string){ + start := time.Now() + fmt.Printf("enter %s:", msg) + return func() { log.Printf("exit %s (%s)", msg, time.Since(start)) } + } + ``` + Now since the defer statement needs to be executed, it needs to evaluate `trace("bigSlowOperation")`, because its return value is what is being defered not itself. And because Anonymous functions have access to named variables defined in enclosing function, it can print out the time elapsed since `start`. +- Deffered functions run *after* return statements have update the function's result variables. +- A deferred anonymous function can observe the function's results + ```golang + func double(x int) (result int) { + defer func() { fmt.Printf("double(%d) = %d\n", x, result) }() + result x + x + } + _ = double(4) + // + // "double(4) = 8" + ``` +- Pay more attention to defer statements in loop bodies. A huge amount of resources might open up but may run out of memory and they might never get closed + + +#### 5.9 Panics +- Usually done by a programmer only for "impossible" situations + + +#### 5.10 + +- if the built-in `recover` function is called within a deferred function and the function containing the `defer` statement is panicking, `recover` ends the current state of panic and returns the panic value. If recover is called any other time, it has no effect and returns nil. +```golang +func Parse(input string) (s *Syntax, err error){ + defer func() { + if p := recover(); p!= nil { + err = fmt.Errorf("internal error: %v", p) + } + }() + // ..parse +} +``` +The deferred function in Parse recovers from a panic, using the panic value to construct an error message. + + +#### 6.1 Method Declarations +- Methods can be declared to any named typed as long as the underlying type is not a pointer or an interface + ```golang + type P *int + func(P) f() { /* ... */ } //compile error: invalid receiver type + ``` +- The method has another parameter called the *receiver* which is a legacy term from OOP. + ```golang + type Number int + func (n Number) Double() int { + return n*2 + } + ``` + Here n is the receiver parameter + +- `*T` and `T` as receiver types + To functions, one takes a `Point` type and the other takes `*Point` + ```golang + + type Point struct{ + X,Y float64 + } + + func (p Point) Distance(q Point) float 64 { + return math.Hypot(q.X-p.X, q.Y-p.Y) + } + + func (p *Point) ScaleBy(factor float64) { + p.X *= factor + p.Y *= factor + } + ``` + 1. Either the receiver argument has the same type as the receiver parameter, Both have type `T` or both have type `*T`: + ```golang + p = Point{1, 2} + pptr = &p + p.Distance(q) //Point + pptr.ScaleBy(2) //*Point + ``` + 2. Receiver argument is a variable of type `T` and the receiver parameter has type `*T` + ```golang + p.ScaleBy(2) //implicit (&p).ScaleBy() + ``` + - Note: We cannot call a `*Point` method on a non-addressable `Point` receiver, because there's no way to obtain the address of a temporary value. + ```golang + Point{1, 2}.ScaleBy(2) // compile error: can't take address of Point literal + ``` + 3. Reciever argument has type `*T` and the receiver parameter has type `T` + ```golang + pptr.Distance(q) //implicit (*pptr).Distance() + ``` +- *`nil` is a valid receiver value for a method, especially when nil is meaningful zero value of the type, like maps and slices* +- According to convention, if one of the methods defined has a pointer receiver of type `T` then all methods should have the pointer receiver type `T` + +#### 6.3 Composing Types by struct Embedding +- **[Read]** +- basically deals with composition in object-orented paradigm. Embedded structs in other struct promote their methods to the struct they are in. Hence the enclosing struct can use its embedded structs mehtods. Just like how when referring to an anonymouse field, we can neglect the struct name itself and go straight to its field. instead `Cirlce.Point.x` just `Circle.x` is enough +- The methods of Point also get promoted to the struct it is embedded in: + ```golang + import "image/color" + type Point struct{ X, Y float64 } + type ColoredPoint { + Point + Color color.RGBA + } + + var cp ColoredPoint + cp.X = 1 + fmt.Println(cp.Point.X) // "1" + cp.Point.Y = 2 + fmt.Println(cp.Y) // "2" + + red := color.RGBA{255, 0, 0, 255} + blue := color.RGBA{0, 0, 255, 255} + var p = ColoredPoint{Point{1, 1}, red} + var q = ColoredPoint{Point{5, 4}, blue} + fmt.Println(p.Distance(q.Point)) + p.ScaleBy(2) + q.ScaleBy(2) + fmt.Println(p.Distance(q.Point)) / "10" + ``` +- An anonymous field can also be a pointer to a named type + ```golang + type ColoredPoint struct { + *Point + Color color.RGBA + } + ``` +- a struct can also have more than one anonymous fields: + ``` golang + type ColoredPoint struct { + Point + color.RGBA + } + ``` + In this case `ColoredPoint` will have all the methods of `Point`, all the methods of `RGBA`. + +#### 6.4 Method Values and Expressions +- Method values is when you have a method and you assign it to a variable `distanceFromP := p.Distance`; here `p` is of the type `Point`. +- Method expression is when you assign the "static" method to a funciton variable, in that case the first argument to that funciton variable will be the reciever argument. `distance := Point.Distance; fmt.Println(distance(p,q))` or scale which takes a `*Point` reciever. `scale := (*Point).ScaleBy` + +#### 6.5 Example: Bit vector +- Did all the exercises 6.1 to 6.5 +- Learnings + - `range` returns a copy of the element and not a pointer to it + - `^` is an xor operation but also a bit complement when used on a single operand + - slices can only be compared to nil. They can't be compared with other slices to check equality. Arrays on the other hand can be compared. + + +#### 6.6 Encapsulation +- Go has one mechanism to control visibility of names - Capilaized are exported and uncapitalized or not. +- Same thing controls the fields of a struct or a method of a type. +- Go stype omits redundant prefix for methods like Get, Fetch, Find, Lookup, etc. + + example, the Logger: + ```golang + package log + + typer Logger struct { + flags int + prefix string + ... + } + + func (l *Logger) Flags() int + func (l *Logger) SetFlags(flag int) + func (l *Logger) Prefix() int + func (l *Logger) SetPrefix(prefix string) + ``` + +#### 7.1 Interfaces as Contracts +- In golang, a type doesn't have to declare all the interfaces it satisfies. Instead it is *satisfied implicitly*. +- An interface is like a contract. If you can satisfy the methods in an interface, then you have implemented that interface +- Interfaces make the behaviour clear. How you do it, is completly up to the programmer implementing the interface +- Example is `io.Writer` and `Fprintf()`. Fprintf wants a `io.Writer` interface as it's first argument and as long as the argument has the `Write()` method, with the correct signature and behaviour it will call it. It doesn't care whether there is actual writing happening anywhere, it only cares that it can call `Write` +- For example, this is a valid implemenation of the Writer interface: + ```golang + type ByteCounter int + func (c *ByteCounter) Write (p []byte) (int, error) { + *c += ByteCounter(len(p)) // convert int to ByteCounter + return len(p), nil + } + + ``` + and since `ByteCounter` satisfies the `io.Writer` contrace, we can pass it to `Fprintf` + ```golang + var c ByteConter + c.Write([]byte("Hello")) + fmt.Println(c) // "5", = len("hello") + + c = 0 // reset + var name = "FooBar" + fmt.Fprintf(&c, "hello, %s", name) + fmt.Println(c) // "13" = len("hello, FooBar") + ``` + +#### 7.3 Interface satisfaction +- A type satisfies an interface if it possesses all the methods the interface requires. +- Assignability of a interface variable applies if both sides have the mehtods required to satisfy the interface: + ```golan + var w io.Writer + w = os.Stdout // OK: *os.File has Write method + w = new (bytes.Buffer) // OK: *bytes.Buffer has Write method + w = time.Second // compile error time.Second lacks Write() method + + var rwc io.ReadWriteCloser + rwc = os.Stdout // OK + rwc = new(bytes.Buffer) // compile error: *bytes.Buffer lacks Close mthod + + w = rwc // OK io.ReadWriteCloser has a Write method + rwc = w // compile error: io.Writer lacks Read and Close method + + + // same with the fmt.String interface + + var s Intset + var _ = s.String() // OK: implicit conversion of s to &s cause *Intset has a String method + var _ fmt.Stringer = &s // OK + var _ fmt.Stringer = s // compile error; Intset doesn't have a String method + ``` +- An interface types wraps and conceals the concrete type and it's value. Only the methods revealed by the interface type maybe called even if the concrete type has others: + ```golang + os.Stdout.Write([]byte("hello")) // OK + os.Stdout.Close() // OK + var w io.Writer + w = os.Stdout + w.Write([]byte("hello")) // OK io.Write has a Write method + w.Close() // compile error. No Close method defined by io.Writer + ``` +- The more methods defined by the interface type, the greater demands are placed on the types that implement it, and the more we know about it's values. +- An empty interface (that which doesn't define any methods) tells us nothing about a type and places no demands on the type that satisfies it. +- At compile time we can have a assertion like so, so that we document the relationship between the interface type and the concrete type. Even though this is not required and interfaces are implicitly satsified by the methods of a type + ```golang + //*bytes.Buffer must satsify io.Writer + var w io.Writer = new(bytes.Buffer) + //or more frugally + + var _ io.Writer =(*bytes.Buffer)(nil) + ``` + +- A pointer to a struct is a common method bearing type. ie. most of the time, these are used to satisfy an interface, but these are not the only ones that can satisfy an interface + +#### 7.5 Interface values +- **Note**: "dynamic value" and "dynamic type" mentioned here are conceptual. In implemenation, the are different things +- Dynamic type and value are assigned (conceptually/internally) when we assign a type that satisfies a interface type to it. + ```golang + var w io.Write + // dynamically assigns the type to *os.File and value as an instance of os.File + w = os.Stdout // implicitly does w = io.Writer(os.Stdout) + + ``` + Read the section for more +- Interface values are comparable and can be used as keys of a map or as the operand of a switch statement +- Two interface values are equal if they have identical dynamic type and if their dynamic values are equal occording to usual behaviour of `==` for the type. If the type is non-comparable, there is a panic: + ```golang + var x interface{} = []int{1,2,3} + fmt.Println(x == x) // panic: comparing uncomparable type []int + ``` +- Only compare interface values if you are certain that they contain dynamic values of comparable types +- We can use `%T` of fmt to report dynamic type of the interface value: + ```golang + var w io.Writer + fmt.Printf("%T\n", w) // "nil" + + w = os.Stdout + fmt.Printf("%T\n", w) // *os.File + ``` +- **7.5.1 Caveat: An interface containing a nil pointer is non-nil** + - **Read seciton** + - If the interface's dynamic type is set to something and the value is nil, the interface variable as a whole is not `nil`, or rather it's value is non-nil (not dynamic value, but its value) + - **Remember** - a nil pointer does still have a type: + ```golang + var w io.Writer + var b *bytes.Buffer + w = b // Ok, but the dynamic type is set to *bytes.Buffer and the value is nil. + w.Write([]bytes("hello")) // will raise compile error. You can still call Write() method on it and it will call the (*bytes.Buffer) Write() method. and the reciever argument will be nil + w == nil // False since it has a dynamic type of *bytes.Buffer + ``` + +#### 7.7 +- Functions can also satisfy an interface and usually these are adapter types whose the sole method and the function itself have the same signature and the job of the method is to just call the function + ```golang + type HandlerFunc func (w ResponseWriter, r *Request) + + func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { + f(w, r) + } + ``` + Here, the type `HandlerFunc` satisfies the interface of `http.Handler`, we can now use this function type anywhere where http.Handler interface type is expected + + +- This trick of functions satisfying an interface allows any other type (such as a struct) to satisfy the interface several different ways. +- Example: + ```golang + func main() { + db := database{"shoes": 50, "socks": 5} + mux := http.NewServeMux() + mux.Handle("/list", http.HandlerFunc(db.list)) // type conversion + mux.Handle("/price", http.HandlerFunc(db.price)) // type conversion + log.Fatal(http.ListenAndServe("localhost:8000", mux)) + } + type dollars float64 + + type database map[string]dollars + + func (db database) list (w http.ResponseWriter, req *http.Request) { + for item, price := range db { + fmt.Fprintf(w, %s: %s\n, item, price) + + } + } + + func (db database) price (w http.ResponseWriter, req *http.Request) { + item := req.URL.Query().Get("item") + price, ok := db[item] + if !ok { + w.WriteHeader(http.StatusNotFound) + fmt.Fprintf(w, "no such item") + return + } + fmt.Fprintf(w, "%s", price) + } + ``` + +#### 7.8 `error` Interface + +- errors package is simple + ```golang + package errors + + func New(text string) error { return &errorString{text} } + type errorString struct {text string} + func (e *errorString) Error() string {return e.text} + ``` +- Pointer type `*errorString` not `errorString` satisfies the interface becase every call to `New` must allocate a distince error instance. We not want distinguished error such as io.EOF to compare equal to one that merely happend to have the same message. +- A nice example of Errno is also given. It satisfies the error interface too, but it's `Error` method also does a lookup for the error no -> error message of the operating system. depedning on the error number, we get different error messages +- + ```golang + var err error = syscall.Errno(2) + fmt.Println(err.Error()) + fmt.Println(err) + ``` + The interface value (err) holds the `type` as syscall.Errno and it's value is `2` + +#### 7.9 Expression Evaluator +- Goes through the process of defining a generic expression evaluator using an interface type: + ```golang + type Var string + type Env map[Var] float64 + type Expr interface { + //Eval returns the value of this Expr in the environment env + Eval (env Env) float64 + //Check reports errors in this Expr and adds its Vars to the Set + Check (vars map[Var]bool) error + } + ``` + Several types of expression are implemented using this.. A Var itself is expression which evaluates to the value of the variable x in the env. And literal just returns it's value, while binary, unary and call (function call) expressions do some evaluation on their arguments. Their arguments and the operation they perform are stored as field values in their structs. Remeber structs are mostly used to satisfy an interface. The section also goes through the testing process in golang briefly. The seciton introduces how one would test something like the expression evaluator very beautifuly. + + +#### 7.10 Type Assertions + +- `x.(T)`. `x` is an expression of an interface type and `T` is a type. +- If the asserted type `T` is a concrete type: + ```golang + var w io.Writer + w = os.Stdout (w: dynamic type = *os.File; dynamic value = os.Stdout) + f := w.(*os.File) // success: f == os.Stdout (extracted the concrete value of the concrete type) + c := w.(*bytes.Buffer) // panic: interface w holds *os.File not *bytes.Buffer + ``` +- If the asserted type `T` is an interface type. It change the type of the expression, making a different (and usually larger p set of methods accessible, but it preserves the dynamic type and value components inside the interface value + ```golang + var w io.Writer + w = os.Stdout + rw := w.(io.ReadWriter) // success: *os.File has both Read and Write + w = new(ByteCounter) // Has write method + rw = w.(io.ReadWriter) // panic: *ByteCounter doesn't have a Read method + ``` +- we can use a second variable to capture whether assertion succeeded or not: + ```golang + var w io.Writer = os.Stdout + f, ok := w.(*os.File) // f == os.Stdout + b, ok := w.(*bytes.Buffer) // failure: !ok, b == nil + ``` +- usually used in an if statement like this: + ```golang + if w, ok := w.(*os.File); ok { + // ... use w + } + ``` + +#### 7.11 Discriminating errors with type assertions +- just goes through how some packages use the type assertions to discriminate the errors and handle them separately + +#### 7.12 Querying behaviors with interface type assertions +- we can use type assertion to other interfaces to see if the dynamic type of an interface also satisfies the other interface +- some io.Writers also have a `WriteString()` method that write a string more efficiently (without making a copy somehow) + ```golang + // writeString writes s to w + // If w has a WriteString method, it is invoked instead of w.Write + func writeString(w io.Writer, s string) (n int, err error) { + type stringWriter interface { + WriteString(string) (n int, err error) + } + if sw, ok := w.(stringWriter); ok { + return sw.WriteString(s) // avoid a copy + } + + return w.Write([]byte(s)) //allocate temp copy + } + func writeHeader(w io.Writer, contentType string) error { + if _, err := writeString(w, "Content-Type: "); err != nil { + return err + } + if _, err := writeString(w, contentType); err != nil { + erturn err + } + } + + ``` +- The `writeString` function above uses a type assertion to see whether a value of a general interface type also satisfies a more specific interface type, and if so, it uses the behavior s of the specific interface. This technique can be put to good use whether or not the queried interface is standard like `io.ReadWriter` or user-define d like `stringWriter`. + +#### 7.13 Type Switches +- There are two ways of using interfaces. One described above where we have a type that satisfies an interface by implemeting it's methods. The emphasis is on the methods (Does the type have that particular method?). If they do have the method, then they are "similar" +- The second way of using interfaces is by using the fact that interface values can hold variety of concrete types. So we can use type assertions to see what type the interface value is holding at the moment. This use of interfaces is called "discriminated union" +- An example used is of the `sql.DB.Exec()` which takes any type and forms a valid sql query string + ```golang + import "database/sql" + + func listTracks(db sql.DB, artist string, minYear, maxYear, int) { + resutl, err := db.Exec( + "SELECT * FORM tracks WHERE artist = ? AND ? <= year AND year <= ?", atist, minYear, maxYear) + ) + } + ``` + The `func sqlQuote(x interface{}) string` does that using type switches: + + + ```golang + func sqlQuote(x interface{}) string { + switch x := x.(type) { + case nil: return "NULL" + case int, uint: + reuturn fmt.Sprintf("%d", x) // x has type interface{} here + case bool: + if x { + return "TRUE" + } + return "FALSE" + case string: + return sqlQuoteString(x) + default: + panic(fmt.Sprintf("unexpected type %%: %v", x, x) + } + } + ``` + The new variable is also called `x`. like a switch statement a type switch implicitly creates a lexical block, so a declaration of a new variable doesn't conflict with outer block. Each case also creates a new lexical block. + +- In a single-type case, the type is the same as in the case. In all other cases `x` has an interface type (like in `case int, uint:` above. +- There are no fall through allowed + + +#### 7.14 Example: Token-based xml decoding + + +#### 7.15 A few Words of advice +- When makeing interfaces, don't make an interface such that it's satisfied by only one type. You can always use export mechanism to hide the methods you don't want of the type to be accessed. +- The exception to this is when you have to have a concrete type to satisfy an interface, but that type can't live in the same package. This way interfaces is used to decouple two packages. +- A good rule of thumb for interface design is *ask only for what you need*. That is is why most of the time, interfaces are small, defining one or two methods only. + +
@@ -0,0 +1,12 @@
+--- +title: noise generators +date: 2022-08-08T21:55:00Z +slug: noise-generators +tags: +- resources +--- + +- https://mynoise.net/ +- https://brainaural.com/ +- https://asoftmurmur.com/ +
@@ -0,0 +1,15 @@
+--- +title: packages, utils and tools +date: 2022-09-01T14:16:00Z +slug: packages-utils-and-tools +tags: +- resources +- tools +--- + +- [broot](https://github.com/Canop/broot) - A new way to see and navigate directory trees +- [hstr](https://github.com/dvorka/hstr) - shell history suggest box - easily view, navigate, search and manage your command history. +- [pasystray](https://github.com/christophgysin/pasystray) - A nice pulse audio system tray written in c +- [GitHub - Canop/rhit: A nginx log explorer](https://github.com/Canop/rhit) + +
@@ -0,0 +1,21 @@
+--- +title: Actually good youtube channels +date: 2022-09-06T08:07:00Z +slug: actually-good-youtube-channels +tags: +- resources +--- + +## Computer Science +1. [Reducible](https://www.youtube.com/c/Reducible/videos) - 3b1b type videos of CS topics +2. [Ben Eater](https://www.youtube.com/c/BenEater/videos) - Computer architecture and electronics +3. [Computerphile](https://www.youtube.com/c/computerphile/videos) - Computer science explained +4. [Zero To ASIC Course](https://www.youtube.com/@ZeroToASICcourse) +## Science +1. [Nils Berglund - YouTube](https://www.youtube.com/c/nilsberglund) + Makes cool simulations +## Infotainment +1. [Asianometry - YouTube](https://www.youtube.com/@Asianometry) + Video essays on business, economics, and history. Sometimes about Asia, but not always. + +
@@ -0,0 +1,14 @@
+--- +title: programming books and articles +date: 2022-10-03T12:47:00Z +slug: programming-books-and-articles +tags: +- resources +- books +--- + +- [Working with Unix Processes](https://workingwithruby.com/downloads/Working%20With%20Unix%20Processes.pdf) +- [Working with TCP Sockets](https://workingwithruby.com/downloads/Working%20With%20TCP%20Sockets.pdf) +- [Beej's Guide](https://beej.us/guide/bgnet/) +- [Use the Index Luke](https://use-the-index-luke.com/) +
@@ -0,0 +1,14 @@
+--- +title: API security +date: 2022-11-14T20:14:00Z +slug: api-security +tags: +- resources +- security +--- + + +- https://owasp.org/www-project-api-security/ +- https://www.youtube.com/playlist?list=PLbyncTkpno5HqX1h2MnV6Qt4wvTb8Mpol +- https://github.com/shieldfy/API-Security-Checklist +- https://github.com/OWASP/crAPI
@@ -0,0 +1,15 @@
+--- +title: example.com equivalent of IP addresses +date: 2023-01-18T00:45:00Z +slug: example-com-equivalent-of-ip-addresses +--- + +The example.com equivalent of IP address is the block of 192.0.2.0/24. + +From rfc-3330 + +> 192.0.2.0/24 - This block is assigned as "TEST-NET" for use in +> documentation and example code. It is often used in conjunction with +> domain names example.com or example.net in vendor and protocol +> documentation. Addresses within this block should not appear on the +> public Internet.
@@ -0,0 +1,15 @@
+--- +title: good computer engineering videos +date: 2023-09-28T21:40:00Z +slug: good-computer-engineering-videos +tags: +- resources +- videos +--- + +## Software +- [How to "think" (and design) like a Software Architect at Silicon Valley Code Camp 2019](https://www.youtube.com/watch?v=mCM6QVHD08c) + +## Hardware +- [The Future of Microprocessors — Sophie Wilson](https://www.youtube.com/watch?v=olXire09ZnE) +
@@ -0,0 +1,14 @@
+--- +title: using different python version with pyenv and poetry +date: 2023-09-29T14:04:00Z +slug: using-different-python-version-with-pyenv-and-poetry +tags: +- python +--- + +1. install pyenv +2. install a python version using `pyenv install 3.9` +3. this should have created a directory `~/.pyenv` +4. tell poetry to use a specific python version - `poetry env use /home/prithu/.pyenv/versions/3.9.18/bin/python` +5. then run `poetry install` +
@@ -0,0 +1,15 @@
+--- +title: 'TIL: AWS s3 folders' +date: 2023-11-15T22:46:00Z +slug: aws-s3-folders +tags: +- aws +- til +--- + +Although s3 has a flat structure—unlike a filesystem—it has a concept of "folders". Folders are 0-byte objects whose key +names end with a '/' When you create a folder from the s3 console it creates +this object automatically and you can manually create it using cli with an +object key ending in '/' + +https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-folders.html
@@ -0,0 +1,9 @@
+--- +title: 'TIL: Cloudfront has a limit on URL length' +date: 2024-01-25T08:51:00Z +slug: til-cloudfront-has-a-limit-on-url-length +--- + +- Make sure that URL lengths are within range 8192 bytes +- Some other services might follow a generic 2000 character limit. +- [http - What is the maximum length of a URL in different browsers? - Stack Overflow](https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers)
@@ -0,0 +1,33 @@
+--- +title: useful git tidbits +date: 2024-02-10T13:05:00Z +slug: usuful-git-tidbits +tags: +- git +- snippets +--- + +1. `--force-with-lease` + +`git push --force-with-lease` -- safer than just `--force` since if it doesn't expect the same commit before the force push to be there as yours, it doesn't push it. + + +2. `git maintenance start` + +makes things faster. Does a bunch of stuff in the config that does automatic stuff in the background using systemd timers + +3. `git blame -w -C -C -C` + +much better than just git blame cause it's smarter about moving of the lines and ignores whitespaces. + +4. `git log -S {regex|string}` + +filter git log output that has the regex in + + +5. `git ls-remote` + +Can be used to pull in the PRs of a remote repository, we don't have to add PR's repo as remotes + + +
@@ -0,0 +1,42 @@
+--- +title: A bash gotcha - command substitution in bashrc +date: 2024-02-14T12:53:00Z +slug: bash-gotcha-command-substitution-backticks-and-dollar-braces-in-bashrc +--- + +I have this alias in my bashrc: + +```bash +alias qn="cd ~/docs/org/0-inbox/ && vim `date +%Y-%m-%d-%H%M`.md" +``` + +which uses Command-Substitution[^2] and basically just makes a "quick note" which I can refer later and move it +a more appropriate place in my organized notes when I have the time. +But when I run this alias it always opens the same note even if I run it at another time. + +TIL that using \` (backticks) or even `$()` in alias this way makes it output +the value when the alias is initialized. So it essentially freezes it's value +when the alias is first sourced. So, If I run this command again at another +time it will still open the same file. Not what is intended. +The solution? Escape the command substitution + +``` +alias qn="cd ~/docs/org/0-inbox/ && vim \`date +%Y-%m-%d-%H%M\`.md" + +``` +Or +``` +alias qn="cd ~/docs/org/0-inbox/ && vim \$(date +%Y-%m-%d-%H%M).md" +``` + +While I am at it let's not cd into the directory shall we? + +``` +alias qn="vim ~/docs/org/0-inbox/\$(date +%Y-%m-%d-%H%M).md" +``` +### Also read +- [command substitution - Backticks vs braces in Bash - Stack Overflow](https://stackoverflow.com/questions/22709371/backticks-vs-braces-in-bash) + + +# Ref +[^2]:[Command Substitution (Bash Reference Manual)](https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html)
@@ -0,0 +1,16 @@
+--- +title: cloudfront proxied dns redirect loop issue +date: 2024-02-19T21:50:00Z +slug: cloudfront-prxied-dns-redirect-loop-issue +tags: +- cloudfront +- cloud +- troubleshoot +--- + +Faced an issue where I would get stuck in a redirect loop when configured a cloudflare dns as 'proxied'. Turns out the solution is to set SSL/TLS mode to 'Full' and that solves it. + + +# Ref +- https://community.cloudflare.com/t/enabling-cloudflare-dns-proxy-results-in-redirect-loop/510465 +
@@ -0,0 +1,23 @@
+--- +title: localhost not resolving for some programs +date: 2024-03-04T22:25:00Z +slug: til-localhost-not-resolving-for-lnd +tags: +- lnd +- troubleshoot +- dns +--- + +# Check your `/etc/hosts` +So ran into this stupid error where lnd was not starting because it was trying to lookup `localhost` and it couldn't resolve it so it asks the DNS server (1.1.1.1) and obviously can't resolve it either. + +``` +failed to load config: lookup localhost on 1.1.1.1:53: no such host + +``` + +Add this to `/etc/hosts` + +``` +127.0.0.1 localhost +```
@@ -0,0 +1,30 @@
+--- +title: python module search path in aws lambda +date: 2024-03-05T15:48:00Z +slug: python-module-search-path-in-aws-lambda +tags: +- python +- aws +- lambda +--- + +When you use an import statement in your code, the Python runtime searches the directories in its search path until it finds the module or package. By default, the runtime searches the `$LAMBDA_TASK_ROOT` (`/var/task`) directory first. If you include a version of a runtime-included library in your image, your version will take precedence over the version that's included in the runtime. + +Other steps in the search path depend on which version of the Lambda base image for Python you're using: + +- **Python 3.11 and later**: Runtime-included libraries and pip-installed libraries are installed in the /var/lang/lib/python3.11/site-packages directory. This directory has precedence over /var/runtime in the search path. You can override the SDK by using pip to install a newer version. You can use pip to verify that the runtime-included SDK and its dependencies are compatible with any packages that you install. + +- **Python 3.8-3.10**: Runtime-included libraries are installed in the /var/runtime directory. Pip-installed libraries are installed in the /var/lang/lib/python3.x/site-packages directory. The /var/runtime directory has precedence over /var/lang/lib/python3.x/site-packages in the search path. + +You can see the full search path for your Lambda function by adding the following code snippet. + +```python +import sys + +search_path = sys.path +print(search_path) +``` + +# Ref +- [Deploy Python Lambda functions with container images - AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/python-image.html) +
@@ -0,0 +1,23 @@
+--- +title: https for local development +date: 2024-03-07T08:31:00Z +slug: https-for-local-development +tags: +- ssl +- linux +--- + +- Use [mkcert](https://github.com/FiloSottile/mkcert) + ``` + mkcert -install + mkcert localhost # creates two localhost.pem (cert) and localhost-key.pem (key) file + ``` +- provide the key and cert file to the http server program. For example in python if using uvicorn: + + ``` + uvicorn.run("api.main:app", host="0.0.0.0", ssl_keyfile=key_path, ssl_certfile=cert_path, reload=True) + ``` +### Also read + 1. [How to Create Your Own SSL Certificate Authority for Local HTTPS Development](https://deliciousbrains.com/ssl-certificate-authority-for-local-https-development/) + 2. [How to Run HTTPS on Localhost: A Step-by-Step Guide](https://akshitb.medium.com/how-to-run-https-on-localhost-a-step-by-step-guide-c61fde893771) +
@@ -0,0 +1,34 @@
+--- +title: make lambda.zip using python poetry +date: 2024-03-07T21:04:00Z +slug: make-lambda-zip-using-python-poetry +tags: +- python +- aws +--- + +``` +poetry build +poetry run pip install --upgrade -t dist/lambda dist/reporter*.whl +cd dist/lambda; zip -r ../lambda.zip . -x '*.pyc'; cd ../../ +``` + + +- If there are problems with some dependencies (GLIBC version mismatch) use + `--platform manylinux2014_x86_64` (or another type of linux pypi package) and + `--only-binary=:all:` + + ``` + poetry run pip install --platform manylinux2014_x86_64 --only-binary=:all: -t dist/lambda dist/reporter*.whl + + ``` + +## without poetry +``` +pip install --platform manylinux2014_x86_64 --only-binary=:all: -r requirements.txt -t /build/lambda + +# add your python package /build/lambda + +cd /build/lambda; zip -r /build/lambda.zip . -x '*.pyc'; cd ../../ + +```
@@ -0,0 +1,20 @@
+--- +title: python logging in aws lambda +date: 2024-03-07T21:34:00Z +slug: python-logging-in-aws-lambda +tags: +- python +--- + +```python +LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper() +logger = logging.getLogger() +logger.setLevel(level=LOG_LEVEL) + + +logger.info("Info log") +logger.info("Error log") +``` + +### Also see +- [amazon web services - Using python Logging with AWS Lambda - Stack Overflow](https://stackoverflow.com/questions/37703609/using-python-logging-with-aws-lambda)
@@ -0,0 +1,27 @@
+--- +title: access cloudflare r2 using aws cli +date: 2024-11-05T23:07:00Z +slug: access-cloudflare-r2-using-aws-cli +tags: +- cloudflare +- s3 +--- + +1. Create R2 tokens from the r2 Overview page. "Manage r2 API Tokens" -> "Create API Token" +3. Copy the access key id and secret access key values +4. Copy the endpoint url. It's of the form `<cloudflare_account_id>.r2.cloudflarestorage.com`. Cloudflare account id is present in the url bar too when you are accessing the cloudflare dashboard and is also displayed in overview page of r2 +4. ~/.aws/config: + ``` + [profile cloudflare] + endpoint_url = https://<cloudlare_account_id>.r2.cloudflarestorage.com + ``` +5. ~/.aws/credentials + ``` + [cloudflare] + aws_access_key_id = <> + aws_secret_access_key = <> + ``` +6. test with: + ``` + aws s3 ls + ```
@@ -0,0 +1,21 @@
+--- +title: installing nixos on oracle cloud arm instance +date: 2024-11-06T12:03:00Z +slug: installing-nixos-on-oracle-cloud-arm-instance +tags: +- nixos +- oracle cloud +--- + +1. Download netboot efi + + ``` + wget https://boot.netboot.xyz/ipxe/netboot.xyz-arm64.efi + ``` +2. Move it to `/boot/efi/` +3. Open cloud shell connection from the instance page. On the instance page it's labeled "Console Connection" under "Resources" +4. "Reboot" the instance +5. Continuously press Esc in the cloud shell. EFI boot manager pops up. Then open the EFI shell and type `fs0:netboot.xyz-arm64.efi` +6. Select NixOS from the netboot menu +7. Install nix os (follow wiki) +
@@ -0,0 +1,24 @@
+# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw?
@@ -0,0 +1,7 @@
+#!/bin/bash + +NOTES_LIST_HTML=/home/prithu/src/website/layouts/notes/list.html +npm run build +rsync --delete -av dist/assets/ /home/prithu/src/website/static/assets +ls dist/assets/*js | xargs basename | xargs -I{} sed -i s/main.*\.js/{}/ $NOTES_LIST_HTML +ls dist/assets/index*.css | xargs basename | xargs -I{} sed -i s/index.*\.css/{}/ $NOTES_LIST_HTML
@@ -0,0 +1,495 @@
+<!DOCTYPE html> +<html lang="en"> + <head> + <title>Imba Project</title> + <link rel="icon" href="data:,"> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <style src="*"></style> + <style src="../../static/css/main.css"></style> + <style src="../../static/css/blog.css"></style> + <style> + html{ + background-color: black; + font-family: Inter; + } + </style> + </head> + <nav> Hello </nav> + <body class=theme-auto> + <div id="_search_app_placeholder"></div> + <div id="_search_app_target" class="container" style="margin-top: 2rem"> + <h2 style=" + margin-bottom:1rem; + font-size:1.8rem; + color: var(--text-primary); + font-weight: 600; + ">Notes</h2> + <div style="margin-bottom:2rem" class="intro-text"> + <p> + This is a place for my notes. Things that are not really post worthy but + are worth saving and sharing. Things like “How to configure nginx to + forward subpath be proxied by an http app correctly” or “How to install nixos on an + oracle cloud vps”, and other useful tidbits. + </p> + </div> + <div id=notes-list> + + <div> + <a href="/notes/installing-nixos-on-oracle-cloud-arm-instance/">installing nixos on oracle cloud arm instance</a> + <div class=tag-group> + + <span>nixos</span> + + <span>oracle cloud</span> + + </div> + </div> + + <div> + <a href="/notes/access-cloudflare-r2-using-aws-cli/">access cloudflare r2 using aws cli</a> + <div class=tag-group> + + <span>cloudflare</span> + + <span>s3</span> + + </div> + </div> + + <div> + <a href="/notes/move-a-running-process-into-tmux-session/">move a running process into tmux session</a> + <div class=tag-group> + + <span>linux</span> + + <span>tmux</span> + + </div> + </div> + + <div> + <a href="/notes/python-logging-in-aws-lambda/">python logging in aws lambda</a> + <div class=tag-group> + + <span>python</span> + + </div> + </div> + + <div> + <a href="/notes/make-lambda-zip-using-python-poetry/">make lambda.zip using python poetry</a> + <div class=tag-group> + + <span>python</span> + + <span>aws</span> + + </div> + </div> + + <div> + <a href="/notes/https-for-local-development/">https for local development</a> + <div class=tag-group> + + <span>ssl</span> + + <span>linux</span> + + </div> + </div> + + <div> + <a href="/notes/python-module-search-path-in-aws-lambda/">python module search path in aws lambda</a> + <div class=tag-group> + + <span>python</span> + + <span>aws</span> + + <span>lambda</span> + + </div> + </div> + + <div> + <a href="/notes/til-localhost-not-resolving-for-lnd/">localhost not resolving for some programs</a> + <div class=tag-group> + + <span>lnd</span> + + <span>troubleshoot</span> + + <span>dns</span> + + </div> + </div> + + <div> + <a href="/notes/cloudfront-prxied-dns-redirect-loop-issue/">cloudfront proxied dns redirect loop issue</a> + <div class=tag-group> + + <span>cloudfront</span> + + <span>cloud</span> + + <span>troubleshoot</span> + + </div> + </div> + + <div> + <a href="/notes/bash-gotcha-command-substitution-backticks-and-dollar-braces-in-bashrc/">A bash gotcha - command substitution in bashrc</a> + <div class=tag-group> + + </div> + </div> + + <div> + <a href="/notes/usuful-git-tidbits/">useful git tidbits</a> + <div class=tag-group> + + <span>git</span> + + <span>snippets</span> + + </div> + </div> + + <div> + <a href="/notes/til-cloudfront-has-a-limit-on-url-length/">TIL: Cloudfront has a limit on URL length</a> + <div class=tag-group> + + </div> + </div> + + <div> + <a href="/notes/aws-s3-folders/">TIL: AWS s3 folders</a> + <div class=tag-group> + + <span>aws</span> + + <span>til</span> + + </div> + </div> + + <div> + <a href="/notes/steam-games-issues-with-fullscreen-in-dwm/">steam games issues with fullscreen in dwm</a> + <div class=tag-group> + + <span>troubleshoot</span> + + <span>steam</span> + + <span>dwm</span> + + </div> + </div> + + <div> + <a href="/notes/using-different-python-version-with-pyenv-and-poetry/">using different python version with pyenv and poetry</a> + <div class=tag-group> + + <span>python</span> + + </div> + </div> + + <div> + <a href="/notes/good-computer-engineering-videos/">good computer engineering videos</a> + <div class=tag-group> + + <span>resources</span> + + <span>videos</span> + + </div> + </div> + + <div> + <a href="/notes/docker-tags-with-repo-name-must-match-the-actual-image/">docker tags with repo name must match the actual image</a> + <div class=tag-group> + + <span>docker</span> + + <span>containers</span> + + </div> + </div> + + <div> + <a href="/notes/til-aws-step-functions-are-damn-useful/">TIL: AWS Step functions are damn useful</a> + <div class=tag-group> + + </div> + </div> + + <div> + <a href="/notes/example-com-equivalent-of-ip-addresses/">example.com equivalent of IP addresses</a> + <div class=tag-group> + + </div> + </div> + + <div> + <a href="/notes/api-security/">API security</a> + <div class=tag-group> + + <span>resources</span> + + <span>security</span> + + </div> + </div> + + <div> + <a href="/notes/programming-books-and-articles/">programming books and articles</a> + <div class=tag-group> + + <span>resources</span> + + <span>books</span> + + </div> + </div> + + <div> + <a href="/notes/csrf-cookie/">CSRF Cookie</a> + <div class=tag-group> + + <span>security</span> + + <span>auth</span> + + </div> + </div> + + <div> + <a href="/notes/actually-good-youtube-channels/">Actually good youtube channels</a> + <div class=tag-group> + + <span>resources</span> + + </div> + </div> + + <div> + <a href="/notes/packages-utils-and-tools/">packages, utils and tools</a> + <div class=tag-group> + + <span>resources</span> + + <span>tools</span> + + </div> + </div> + + <div> + <a href="/notes/noise-generators/">noise generators</a> + <div class=tag-group> + + <span>resources</span> + + </div> + </div> + + <div> + <a href="/notes/learning-golang/">the go programming language book notes</a> + <div class=tag-group> + + <span>golang</span> + + </div> + </div> + + <div> + <a href="/notes/freedom-of-monetary-transaction/">Freedom of Monetary Transaction</a> + <div class=tag-group> + + <span>bitcoin</span> + + <span>freedom</span> + + <span>blog</span> + + </div> + </div> + + <div> + <a href="/notes/aws-s3-access-policy-nuances/">AWS S3 access policy nuances</a> + <div class=tag-group> + + <span>aws</span> + + </div> + </div> + + <div> + <a href="/notes/aws-resource-policies/">AWS Resource policies</a> + <div class=tag-group> + + <span>aws</span> + + </div> + </div> + + <div> + <a href="/notes/sqlite-and-lightweight-infra/">sqlite and lightweight infra</a> + <div class=tag-group> + + <span>infra</span> + + <span>database</span> + + </div> + </div> + + <div> + <a href="/notes/eks-vs-ecs-vs-fargate/">EKS vs ECS vs Fargate</a> + <div class=tag-group> + + <span>aws</span> + + <span>cloud native</span> + + <span>containers</span> + + </div> + </div> + + <div> + <a href="/notes/using-xxd-to-create-binary-data/">using xxd to create binary data</a> + <div class=tag-group> + + <span>cli</span> + + <span>unix</span> + + </div> + </div> + + <div> + <a href="/notes/playwright-is-really-good-for-browser-automation/">playwright is really good for browser automation</a> + <div class=tag-group> + + <span>automation</span> + + <span>webdev</span> + + </div> + </div> + + <div> + <a href="/notes/literal-ipv6-in-urls/">TIL: literal ipv6 in URLs</a> + <div class=tag-group> + + <span>networking</span> + + <span>TIL</span> + + </div> + </div> + + <div> + <a href="/notes/setting-up-cgit-with-nginx/">setting up cgit with nginx</a> + <div class=tag-group> + + <span>nginx</span> + + <span>linux</span> + + </div> + </div> + + <div> + <a href="/notes/resources-to-learn-about-aws-vpc/">resources to learn about aws vpc</a> + <div class=tag-group> + + <span>aws</span> + + <span>resources</span> + + </div> + </div> + + <div> + <a href="/notes/nginx-reverse-proxy-and-url-rewrite/">nginx reverse proxy and url rewrite</a> + <div class=tag-group> + + <span>nginx</span> + + </div> + </div> + + <div> + <a href="/notes/keeping-it-simple-dense-and-precise/">keeping it simple dense and precise</a> + <div class=tag-group> + + <span>meta</span> + + <span>zet</span> + + </div> + </div> + + <div> + <a href="/notes/starting-zettelkasten/">starting zettelkasten</a> + <div class=tag-group> + + </div> + </div> + + <div> + <a href="/notes/python-one-liners-using-list-composoition/">python one-liners using list composoition</a> + <div class=tag-group> + + <span>python</span> + + <span>unix</span> + + </div> + </div> + + <div> + <a href="/notes/reversing-a-firmware-of-security-camera-and-squashfs/">reversing a firmware of security camera and squashfs</a> + <div class=tag-group> + + <span>security</span> + + <span>reverse engineering</span> + + <span>firmware</span> + + </div> + </div> + + <div> + <a href="/notes/dependency-chain-attack-on-magneto/">dependency chain attack on magneto</a> + <div class=tag-group> + + <span>security</span> + + <span>infosec</span> + + </div> + </div> + + <div> + <a href="/notes/physical-pen-testers/">physical pen testers</a> + <div class=tag-group> + + <span>security</span> + + <span>infosec</span> + + </div> + </div> + + </div> + </div> + <footer> Hello </footer> + + <script type="module" src="./src/main.imba"></script> + </body> +</html>
@@ -0,0 +1,1140 @@
+{ + "name": "search-notes", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "search-notes", + "devDependencies": { + "imba": "^2.0.0-alpha.237" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-0.1.1.tgz", + "integrity": "sha512-LyB/8+bSfa0DFGC06zpCEfs89/XoWZwws5ygEa5D+Xsm3OfI+aXQ86VgVG7Acyef+rSZ5HE7J8rrxzrQeM3PjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "find-up": "^5.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/envinfo": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fdir": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz", + "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/imba": { + "version": "2.0.0-alpha.237", + "resolved": "https://registry.npmjs.org/imba/-/imba-2.0.0-alpha.237.tgz", + "integrity": "sha512-pX5ongVv28WnMy79kCB/G7qXoWluwqjudD8iv2GaL1or0c0kPEAIafRLH6iKKEc1AryZ5o4E1lDLTeqQ7xKhcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^0.1.1", + "chokidar": "^3.4.3", + "colord": "^2.9.3", + "cross-spawn": "^7.0.3", + "debug": "^4.3.4", + "dotenv": "^16.0.3", + "envinfo": "^7.8.1", + "esbuild": "^0.15.2", + "fdir": "^6.1.0", + "get-port": "^5.1.1", + "local-pkg": "^0.4.2", + "lodash.mergewith": "^4.6.2", + "prompts": "^2.4.2" + }, + "bin": { + "imba": "bin/imba", + "imbac": "bin/imbac" + }, + "engines": { + "node": ">=13.10.0" + }, + "peerDependencies": { + "@testing-library/dom": "*", + "@testing-library/jest-dom": "*", + "vite": "*", + "vite-node": "*", + "vitest": "*" + }, + "peerDependenciesMeta": { + "@testing-library/dom": { + "optional": true + }, + "@testing-library/jest-dom": { + "optional": true + }, + "vite": { + "optional": true + }, + "vite-node": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +}
@@ -0,0 +1,11 @@
+{ + "name": "search-notes", + "scripts": { + "dev": "imba -w index.html", + "build": "imba build index.html", + "preview": "npx vite preview" + }, + "devDependencies": { + "imba": "^2.0.0-alpha.237" + } +}
@@ -0,0 +1,1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg>
@@ -0,0 +1,110 @@
+import search from './assets/img/search.svg' + +def fetchNote slug + let res = await window.fetch("./{slug}/index.json") + try + return await res.json! + catch + return null + +tag note-content + css h2 mb:4 c:$text-primary + css c:$text + + def routed params, state + note = state.note ||= await fetchNote params.slug + p = document.createElement('p') + p.classList.add "post-text" + p.innerHTML = note ? note.content : "" + + <self [o@suspended:0.4]> + (<h2> note.title + <p[c:$text my:3]> note.date + <div.post-labels> + if note.tags + for t in note.tags + <p.post-label> t + p) if note + + +tag note-item + prop note + css pl:4 pr:4 + my:10px + + css + a@hover text-decoration: underline + a c: $text + fw.active: 600 + c.active: $text-primary + <self> + <a route-to="/notes/{note.url.split('/').slice(-2,-1)}"> note.title + +tag app + target + notes = [] + introBox + searchQuery + css d:flex jc:center x:-180px + + css .left d:vflex ai:left jc:start gap:2 w:296px mr:16 max-height:calc(100vh - 96px - 112px) min-height:80 pos:sticky top: 96px + css .note-list ofy:scroll + overscroll-behavior: none + + css .center w:664px + + css + input bgc:transparent outline:none bd:none c:$text p:0 w:100% + .searchbar bgc:$card-bg d:hflex px:4 py:1 rd:3 gap:2 mb:2 + olc:$imba-searchbar-outline-color olw:$imba-searchbar-outline-width ols:$imba-searchbar-outline-style + .center h2 mb:4 + + def escapeRegExp(str) + str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + + def fuzzyMatch(query, string) + pattern = query.trim().split(' ').map(do(l) "{escapeRegExp(l)}").join("|"); + const re = new RegExp(pattern, "i") + return re.test(string) + + + def setup + for c in target.children + if c.id == 'notes-list' + for n in c.children + anchor = n.children[0] + let note = {} + note.title = anchor.innerHTML + note.url = anchor.href + notes.push note + elif c.className == 'intro-text' + introBox = c + + imba.unmount target + + <self> + <div.left> + <div.searchbar> + <svg src=search width=18px [fill:$text]> + <input bind=searchQuery> + <div.note-list.vert-scroller> + for note in notes + if !searchQuery + <note-item note=note> + else + // <note-item note=note> if note.title.toLowerCase!.indexOf(searchQuery) >= 0 + <note-item note=note> if fuzzyMatch(searchQuery, note.title) + <div.center> + <div route="/notes/"> + <h2[c:$primary-text]> "Notes" + introBox + <note-content route="/notes/:slug"> + + +var root = document.getElementById '_search_app_target' +var placeholder = document.getElementById '_search_app_placeholder' +let appc = <app target=root> +if root + imba.mount appc, placeholder +else + console.log("no element with _search_app id found")
@@ -6,10 +6,8 @@ {{ partial "nav.html" }}
<section id="intro" class="page-section"> <div class="container"> - <div id="intro-text"> - <p> + <div class="intro-text"> {{ .Content }} - </p> </div> </div> </section>
@@ -0,0 +1,42 @@
+{{ partial "head.html" . }} +<body class=theme-auto> + {{ partial "nav.html" }} + <link rel='stylesheet' href='/assets/index.REPLACED.css'> + <div id="_search_app_placeholder"></div> + <div id="_search_app_target" class="container" style="margin-top: 2rem"> + <h2 style=" + margin-bottom:1rem; + font-size:1.8rem; + color: var(--text-primary); + font-weight: 600; + ">Notes</h2> + <div style="margin-bottom:2rem" class="intro-text"> + <p class=post-text> + + A place for my notes—things that are not really post worthy but are + worth saving. These are things that would answer a question, for example, + "how do I rewrite urls for proxying an http app using nginx + again?"<sup><a href="./nginx-reverse-proxy-and-url-rewrite">1</a></sup> + or “how did I install nixos on a oracle cloud vps last time?”<sup><a + href="./installing-nixos-on-oracle-cloud-arm-instance">2</a></sup> + Also, TILs and other usueful tidbits + + </p> + </div> + <div id=notes-list> + {{ range .Pages.ByDate.Reverse }} + <div> + <a href="{{ .RelPermalink }}">{{ .Title }}</a> + <div class=tag-group> + {{ range .Params.tags }} + <span>{{ . }}</span> + {{ end }} + </div> + </div> + {{ end }} + </div> + </div> + <script type="module" src='/assets/main.REPLACED.js'></script> +</body> +{{ partial "footer.html" . }} +</html>
@@ -0,0 +1,6 @@
+{{- $pages :=.Pages }} +{{- $out := slice }} +{{- range $pages }} +{{- $out = $out | append (dict "title" .Title "slug" .Params.slug "tags" .Params.tags "path" .RelPermalink ) }} +{{- end }} +{{- $out | jsonify}}
@@ -0,0 +1,21 @@
+{{ partial "head.html" . }} +<body class="theme-auto"> + {{ partial "nav.html" }} + <div class="bcontainer" style="max-width:720px"> + <div class="bcontent"> + <h1>{{ .Title }}</h1> + <p class="post-date">{{ .Date.Format "02 January, 2006" }}</p> + <div class="post-labels"> + {{ range .Params.tags }} + <div class=post-label>{{ . }}</div> + {{ end }} + </div> + <div class="post-text"> + {{ .Content }} + </div> + </div> + </div> + {{ partial "footer.html" . }} +</body> +</html> +
@@ -0,0 +1,1 @@
+{{- (dict "title" .Title "slug" .Params.slug "tags" .Params.tags "path" .RelPermalink "content" .Content "date" (.Date.Format "02 Jan, 2006") ) | jsonify }}
@@ -28,7 +28,7 @@ <item>
<title>{{ .Title }}</title> <link>{{ .Permalink }}</link> <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate> - {{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}} + {{ with .Site.Params.Author.email }}<author>{{.}}{{ with $.Site.Params.Author.name }} ({{.}}){{end}}</author>{{end}} <guid>{{ .Permalink }}</guid> <description>{{ .Content | html }}</description> </item>
@@ -164,6 +164,7 @@ }
.post-text li{ line-height: 1.6; + margin-bottom: 8px; } .post-text h1{
@@ -14,6 +14,9 @@ outline: none;
text-decoration: none; color: var(--text); } +a:hover{ + text-decoration: underline; +} ::selection { background-color: #5ba6e6;@@ -60,7 +63,11 @@ --logo-bottom: var(--light-logo-bottom);
--pre-bg: var(--light-pre-bg); --pre-border: var(--light-pre-border); --code-bg: var(--light-code-bg); - --scrollbar: #00000021; + --scrollbar: #00000011; + + --imba-searchbar-outline-width: 1px; + --imba-searchbar-outline-style: solid; + --imba-searchbar-outline-color: #00000022; } @media (prefers-color-scheme: dark) {@@ -79,6 +86,7 @@ --pre-bg: var(--dark-pre-bg);
--pre-border: var(--dark-pre-border); --code-bg: var(--dark-code-bg); --scrollbar: #ffffff11; + --imba-searchbar-outline-style: none; } }@@ -97,12 +105,33 @@ --pre-bg: var(--dark-pre-bg);
--pre-border: var(--dark-pre-border); --code-bg: var(--dark-code-bg); --scrollbar: #ffffff11; + + --imba-searchbar-outline-style: none; } body{ background-color: var(--bg); font-family: Inter, sans-serif; } + +.vert-scroller::-webkit-scrollbar { + margin-left:12px; + width: 6px; +} + +.vert-scroller:hover::-webkit-scrollbar-thumb { + background-color: rgb(from var(--scrollbar) r g b / 0.2); +} + +.vert-scroller::-webkit-scrollbar-thumb { + background-color: var(--scrollbar); + border-radius: 20px; +} + +.vert-scroller::-webkit-scrollbar-thumb:active { + background-color: rgba(3,122,255,0.8); +} + nav { font-family: Inter;@@ -280,6 +309,14 @@ position: relative;
max-width: 664px; } +.sidebar-layout-container{ + display: flex; +} + +.sidebar-layout-main-content { + width: 664px; +} + .shadow-box{ background-color: var(--card-bg); border-radius: 24px;@@ -328,7 +365,7 @@ font-weight: 100;
text-shadow: 0 4px 7px rgba(0,0,0,0.2); } -#intro-text{ +.intro-text{ color: var(--card-text); padding: 1rem 1.9rem; font-family: 'Inter', sans-serif;@@ -340,8 +377,30 @@ box-shadow: 0 3px 8px rgba(0,0,0,0.075);
margin: 0 auto; } -#intro-text p { - margin-bottom: 0.9rem; +.intro-text p { + margin: 0.9rem 0rem; +} + +#notes-list > div { + display: flex; + justify-content: space-between; + margin: 16px 0; +} + +.tag-group { + display:flex; + justify-content: flex-end; + flex-wrap: wrap; + gap: 10px; + +} + +.tag-group span{ + font-size: 14px; + border: 1px; + background-color: var(--card-bg); + padding: 4px 12px; + border-radius: 36px; } .joke {