<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Anees Iqbal's Blog</title>
        <link>https://aneesiqbal.ai</link>
        <description>Personal blog feed of Anees Iqbal</description>
        <lastBuildDate>Mon, 16 Mar 2026 02:19:52 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>All rights reserved 2026, Anees Iqbal</copyright>
        <item>
            <title><![CDATA[Walled Gardens Can Kill]]></title>
            <link>https://aneesiqbal.ai/2025-04-18-walled-gardens-can-kill</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2025-04-18-walled-gardens-can-kill</guid>
            <pubDate>Fri, 18 Apr 2025 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
I'm an Apple ecosystem user, owning an iPhone ever since a past employer got it for me to test our company app some 8 years ago. Over time, as I've upgraded, I've also incrementally moved over my family to the ecosystem, replacing our hp/dell laptops with macbooks and Samsung Galaxy phones with Apple iPhones.

Apple's application ecosystem is pretty famously locked down. You cannot side load applications onto your iPhone, quite as easily as you can with an Android. There has been some legislative push to change this (with the EU enacting the Digital Markets Acts or DMA) but the sentiments among lawmakers and users are still divided.

I didn't feel strongly about this, one way or the other until the experiences of last week. My wife suddenly fell ill and we had to figure out which hospital to go to, we were ill-prepared for this situation as we hadn't installed the insurance providers' application to check the in-network hospitals.

Unfortunately for us, the insurance app is geo-restricted to United Arab Emirates (UAE) and Apple refused to install it on my phone. Normally this would be a simple problem to fix, just go to your Apple account settings and switch the region, but this too was denied, as I had the yearly Apple Music subscription. Changing the region in this case required calling Apple Support to cancel the yearly Apple Music subscription first, and we didn't have the time for this.

Luckily I was prototyping with the idea of an Android Application the past week so I had the Android Emulator in my laptop, which I used to install the application, add our insurance information and figure out where to go. Just to be safe, I also ordered an Android phone to be delivered to me while I went to the hospital, where I used my iPhone's hotspot to set it up and show all the insurance information to the hospital staff.

Had I not prototyped the Android Application the week prior, or had Android similarly locked down their ecosystem, we would've been in a much worse situation. This experience has significantly changed my opinions on the matter, I now carry a spare Android phone at home with all the insurance information loaded *just in case*.

Walled Gardens can kill. I hope Apple, the lawmakers and users will reconsider their stance and consider a worldwide DMA-like law to prevent others from falling down the same path.
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What I learned flashing an EEPROM]]></title>
            <link>https://aneesiqbal.ai/2020-09-21-what-i-learned-flashing-an-eeprom</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2020-09-21-what-i-learned-flashing-an-eeprom</guid>
            <pubDate>Mon, 21 Sep 2020 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
### Context:

I used to travel with two laptops, a gaming laptop and a macbook for work on the go. I couldn't carry a single laptop for both tasks in the past because I needed 4k for design work and a fast refresh rate display for smooth gaming. I recently upgraded to a Razer Blade Pro 17 2020 to fulfill this goal, it boasts a 4k 120hz OLED Touch Display. I needed some BIOS configurations to make it work for my usecase. The BIOS came locked on this machine by the manufacturer so I had to reflash the BIOS with a hardware programmer.

### What I used:

I used a CH341A USB programmer on Windows paired with ASProgrammer. Instead of desoldering the BIOS from the Laptop Mobo and resoldering it on the programmer and back, I used the SOIC8 SOP8 Test Clip. You may want to order more than one as the first one I tried turned out to be faulty.

### What I learned from this experience:

- If your machine boots, use that as an opportunity to extract as much information as you can about the BIOS you're about to flash. The programmer needs to know the exact model, otherwise the flashing won't work. Most programmers have a chip-detection feature but it can be spotty.
- Download a BIOS update from the manufacturer, and dump the BIOS from the chip. Make sure that they both have the same size. Most BIOS update executables from manufacturers can be unzipped to extract the BIOS fw.
- Make sure to erase the BIOS before writing. If you just dump and write, the programmer will skip over the zero-bytes leaving you with a corrupt BIOS fw. Some programmers have an erase-flash-verify feature, use that if you can.
- Practice on a dual-BIOS Computer Motherboard if you can, that'll greatly lower your chances of failure in your first attempt.
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What I don't like about Node.js]]></title>
            <link>https://aneesiqbal.ai/2020-05-17-what-i-dont-like-about-node-js</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2020-05-17-what-i-dont-like-about-node-js</guid>
            <pubDate>Sun, 17 May 2020 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
[Node.js][] is a JavaScript runtime built on Chrome's V8 JavaScript engine. I have been working with Node.js for many years and for the most part, it has been a pleasant and productive experience. The prototyping speed and ability to scale that same quickly written and not particularly optimized code is amazing. It often falls short when you do try to optimize tho, you hit the architectural limitations faster than you expect to.

Please keep in mind that this rant is a product representing its time, so if you are reading this in the future, It may no longer be true, or I would hope so.

Short version: No proper multi threading with atomic object access.

Long version:

My personal experience with the short comings of Node.js comes as a result of trying to write a *fast* module bundler in Node.js. In case you don't know, a module bundler like [Webpack][], [Rollup][], [Parcel][] or my own (now deprecated) [Pundle][] is a piece of software that takes your program and its dependencies and bundles them up into a single file or sometimes chunks often to be consumed by browsers. Module bundlers are what let you `require(...)` or `import(...)` dependencies in the browser without the hassle of writing all those `<script ...>` tags by hand (and having to maintain the order of dependencies). You can configure them to do much more than that but that's the gist of it.

For a module bundler to become widely successful, it has to be configurable, work well and be reasonably fast. Now the configurability and being reasonably fast are difficult to achive together as I have come to learn through experience. For example, if you control all the steps in the pipeline, you only have to parse the file once and continue to work on AST from then onwards. Making it configurable means that each step much pass on the resultant string or buffer to the next step. Most module bundlers of current time work this around by manipulating strings directly using [magic-string][] or something similar to it. Using it allows you to infer trivial things and replace imports with internal references. Making the pipeline configurable however means that someone could put Babel transpilation or Terser minification in there, so your direct-string-manipulation isn't going to stop parsing and re-parsing.

Another thing that makes this very difficult, if not impossible to scale with the number of cores is the fact that you cannot share objects between threads in Node.js. IPC in Node.js is quite expensive, expensive enough that you have to architect your module bundler so that one process does nothing but task the others and even then, it ends up being bottle-necked because of IPC overhead of serializing and unserializing these thousands of files and their state at different steps in the pipeline, not to mention that if you want to avoid re-parsing the file, AST is much much bigger than the source and you **require** most metadata of all the files in a bundle to generate a source map. Node.js only recently got proper multi threading support via [`worker_threads`][], but even that does not allow sharing actual objects, only transferring ownership of Buffers.

The source of lack of ability to transfer objects instead of Buffers, per my unverified source is that v8 locks the entire virtual machine to all threads when you try to call something in parallel. So your module bundler is limited by the fundamental limitations of the v8 engine. It's like trying to run a horse race with only one horse. You cannot work around it.

[JavascriptCore][] (the JS engine used inside Safari) does not however lock the entire virtual machine but only the specific execution context. There was an attempt by [@voodooattack][] to create a runtime on top of it to rival (if not compliment) Node.js. It is called [Nexus.js][] and available on Github. It supports [Concurrent Variable Access][] among other cool things but sadly hasn't gotten the love it deserved. Most Module Bundlers, if they were just ported to Nexus.js with no changes other than to remove their current worker pooling implementations would run many many times faster.

Alas.

Further reading:

- [Locking in Webkit - Webkit Blog](https://webkit.org/blog/6161/locking-in-webkit/)

[Node.js]:https://nodejs.org/en/
[Webpack]:https://webpack.js.org/
[Rollup]:https://rollupjs.org/
[Parcel]:https://parceljs.org/
[Pundle]:https://github.com/steelbrain/pundle
[magic-string]:https://github.com/Rich-Harris/magic-string
[`worker_threads`]:https://nodejs.org/api/worker_threads.html
[JavascriptCore]:https://developer.apple.com/documentation/javascriptcore
[@voodooattack]:https://github.com/voodooattack
[Nexus.js]:https://github.com/voodooattack/nexusjs
[Concurrent Variable Access]:https://www.nexusjs.com/architecture/#concurrent-variable-access
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How imports are handled in Pundle]]></title>
            <link>https://aneesiqbal.ai/2018-07-09-how-imports-are-handled-in-pundle</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2018-07-09-how-imports-are-handled-in-pundle</guid>
            <pubDate>Mon, 09 Jul 2018 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
This post is a part of the series ["An Intro to Pundle"][pundle-intro].

---

Imports are a way of sharing bindings between modules. Imports help keep the code modular and maintainable as the size of the codebase grows as well as sharing it with other people trying to solve similar problems (think [npmjs][]).

In Javascript runtimes like V8 (heart of Chrome browser and Node.js) you can import JS files into JS files but you cannot for example import CSS files into JS files. Being able to import CSS into JS would help modularize the code further and help avoid any conflicts on the global css namespace.

Interoperability between asset types as different as JS and CSS (compared to say JS and WASM) requires a lot of decisions that are better done by the bundler instead of runtime. For example, whether to use the contents of the asset or export a path pointing at it because the size of the asset is too big (think 150kb+ of blob, wouldn't make sense in a JS bundle).

While other module bundlers try to hard-code how the bridges work between types in the core, Pundle takes a different approach. Pundle's file resolver allows users to specify completely arbitrary "format"s to use for each extension. Pundle enforces "chunk"s to have the same format throughout so when you import a css file or a golang file or any other non-js format file, It'll be force loaded as `js` as to allow the transformers to provide "bridge" code.

While providing the bridge code the transformers can add the import as a chunk dependency and return path to it or return it as base64 blob etc. For css this lets us do interesting things like return the [css modules object][css-modules] to the requiring module or insert css into a JSON blob that accepts HMR during development.

For example, here's what happens when your import `./index.js` imports an `./index.css`

- Resolve `./index.js` relative to project root
- Resolved to `project/index.js` with format `js`
- Process `project/index.js` as `js` and scan for imports
- Resolve `./index.css` relative to `./index.js`
- Resolved to `project/index.css` with format `css`
- Process `project/index.css` as `js` and scan for imports (notice how we're processing as `js`)
  - If the file contains with `.module` before its extension like (`.module.css`), return its module mapping back to JS
  - If HMR and Development are turned on, put the raw contents as blob to create a style tag to be replaced on HMR later
    - Otherwise add `project/index.css` with format `css` as an external dependency of the file

This process depending on your configuration would either embed the css in JS file or add it as an external dependency (while also resolving its imports and adding them as dependencies recursively). This allows Pundle to maintain multiple versions of the same file with different formats. Handling imports like this allows for an unprecedented level of customizable interoperability between different formats.

[pundle-intro]: /2018-07-09-an-intro-to-pundle
[npmjs]: https://docs.npmjs.com/getting-started/what-is-npm
[css-modules]: https://github.com/css-modules/css-modules
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How HMR in Pundle works]]></title>
            <link>https://aneesiqbal.ai/2018-07-09-how-hmr-in-pundle-works</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2018-07-09-how-hmr-in-pundle-works</guid>
            <pubDate>Mon, 09 Jul 2018 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
This post is a part of the series ["An Intro to Pundle"][pundle-intro].

---

HMR (Hot Module Replacement) is a way to apply changes to parts of the app while it's still running allowing developers to quickly test new changes and be more productive. Webpack has a [great introduction to HMR][hmr-webpack]. I recommend you read it before reading through the rest of the post.

Here are some of the interesting things about Pundle's implementation of HMR

#### Determining HMR server path:

Both Webpack and Parcel use [WebSockets][ws] to deliver HMR to the clients. These can be a bit hard to develop / maintain because to handle WebSocket connections on the server side you have to either listen on a separate port for HMR (if source is on https, then you have to have https on ws too) or you have to provide the server object to the WebSocket libs (which means it cannot be an express middleware).

That leads to extra moving parts in the config, `hmrHost` or `hmrPath`. Pundle solves this by getting rid of WebSockets and using `fetch()` streaming instead. Fetch streaming works on normal HTTP requests so it can be done in an express middleware and does not need any third party library. For paths, Pundle uses `document.currentScript` + `.hmr.pundle` and then handles it as a route on the server.

As HMR is part of the development workflow, you don't have to worry about supporting fetch streaming in older browsers as long as your own is up to date.

#### Compiling and applying changes

While Webpack uses a poll mechanism to determine if files have changed, Pundle makes the server do the heavy lifting. It writes HMR payloads to an internal list of streaming http requests. Pundle's architecture allows it to generate individual files as temporary chunks, meaning that even if your bundle is 100mbs in size, only changed files would be transformed and sent to the client. This gives Pundle `O(nFilesChanged)` instead of `O(nFilesTotal)` time complexity for HMR.

Pundle also only regenerates a full bundle (ie joining all the transformed files together) only when it receives the next non-HMR request meaning that if you keep saving your files without refreshing, your CPU cycles won't be wasted.

---

If you would like to read the source code of the HMR client (at the time of writing this post), You can [hmr-client on Github](https://github.com/steelbrain/pundle/blob/192131782c9c76180cc6824cd1094955b3521e0f/packages/pundle-dev-middleware/src/client/hmr-client.js)

[pundle-intro]: /2018-07-09-an-intro-to-pundle
[hmr-webpack]: https://webpack.js.org/concepts/hot-module-replacement/
[ws]: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[An Intro to Pundle]]></title>
            <link>https://aneesiqbal.ai/2018-07-09-an-intro-to-pundle</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2018-07-09-an-intro-to-pundle</guid>
            <pubDate>Mon, 09 Jul 2018 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
[Pundle][pundle-gh] (Peaceful Bundle) is a next generation module bundler. It allows you to use Node.js style require statements in the browser and supports splitting out of the box with [`import()`][import-rfc] syntax. It uses worker processes to parallelize the work as much as possible, that combined with a file system transform cache delivers amazing performance on recurrent builds.

You can read how it works in this series of posts:

- [How imports are handled in Pundle](/2018-07-09-how-imports-are-handled-in-pundle)
- [How HMR in Pundle Works](/2018-07-09-how-hmr-in-pundle-works)

---

This series of posts is a Work-in-Progress and would be updated as Pundle furthers it's path towards release.

[pundle-gh]: https://github.com/steelbrain/pundle
[import-rfc]: https://github.com/tc39/proposal-dynamic-import
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Feminism vs Equality]]></title>
            <link>https://aneesiqbal.ai/2018-03-08-feminism-vs-equality</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2018-03-08-feminism-vs-equality</guid>
            <pubDate>Thu, 08 Mar 2018 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
Today is the 8th of March and is also the International Women's day. While the media outlets use this day to promote a few women who did great things, I would like to pay respect and remember today the women who don't get as much recognition but work very hard everyday to take care of their families and societies. These are our mothers, daughters, sisters and partners around the world.

It's uplifting how the awareness against unjust treatment for women is raising around the world. We have come a long way from when [women were burnt alive when their husbands died][1] to when women are bosses in major institutions. But our struggle for justice is not over. True equality for all is possible only when we all try to do our part in ensuring equal opportunities and treatment for women around the world.

Countless movements around the world are pursuing this goal and among them is the Feminist movement. Like all the non-moderated public movements, it has a lot of flavors. In Feminism, there are people who want equality for all, and there are people who think women should have unfair advantage, both these groups living under the same umbrella.

Inequality against men is just as bad as inequality against women. Please stop using the word feminism for equality. If you believe in equality for all people regardless of gender, you are an equalist. Please do not associate yourself with people who are like the ones you are advocating against.

Thank You.

[1]: https://en.wikipedia.org/wiki/Sati_(practice)
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why Reason?]]></title>
            <link>https://aneesiqbal.ai/2017-11-22-why-reason</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2017-11-22-why-reason</guid>
            <pubDate>Wed, 22 Nov 2017 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
Reason is a way to think properly while avoiding obstacles like bias, faith, emotions and beliefs. Reason is ultimately a tool for finding the truth. Instead of giving one person the authority to declare what is right and what is not, reason divides that authority among individuals.

Neither knowing the truth makes one reasonable, nor not knowing the truth makes one unreasonable. It's the thought that "The person I am engaged in a discourse with might know something I do not. I might be wrong. I might learn something new." As proven by Machine Learning in digital systems where neurons execute over datasets of millions, "<b>On a large enough scale, quantity compensates for quality.</b>" Thus, reason helps make societies where laws are fair, equal and enforced on all.

In a reasonable society, we take risks every time we make a statement. If the statement is verified, we gain trust of others or establish ourselves as liars otherwise. But the statements are not always verifiable, in which cases the liars would have a hard time convincing people of their occasional truth than truth tellers of their occasional lies.

The modern age of technology makes connection to the entire world incredibly easy. While it exposes us to people of vastly different cultures and beliefs, it also allows us to connect with millions of other people that think the way we do. People of the latter kind end up in an echo chamber that amplifies their thoughts ten folds. This pushes them further into the cave of ignorance and farther from the truth reason promises.

I have lost track of how many times I've seen a celebrity say things like "[Name] is a horrible person" without stating why they think that, which results in a backlash from supporters of the person referenced, which are again offensive statements without reason. This continues until the original poster claims the backlash is because of their race or gender and does still not explain why they said what they did.

Actions such as these are not only condescending but also very counter-productive. They do not encourage improvement while discouraging current behavior. The next time someone claims on Twitter, that someone else is a terrible person, don't reply to them saying they are a terrible person for posting this. Instead, ask for their reasoning and proof so you can dismiss it or believe it based on your criteria of truth.
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to be Happy]]></title>
            <link>https://aneesiqbal.ai/2017-06-10-how-to-be-happy</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2017-06-10-how-to-be-happy</guid>
            <pubDate>Sat, 10 Jun 2017 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
Happiness is a feeling. It's not something we can eat or drink, it's something we feel as a result of certain events. But even more important than that, Happiness is a result of the way we perceive the world.

Since the beginning of this year, I have chased happiness directly. I have tried different ways, while most of them have been unsuccessful, a small amount of them worked, or so I thought.

My initial experiment was with Pizza. Pizza used to make me happy, I used to have it once or twice a month but because I was chasing happiness this time, I started having it more than twice a week. Having a Pizza so often turned out to be unhealthy and it upset my stomach. The important thing here is that it lost it's charm it used to have. I stopped getting excited for Pizza. I liked it's taste but it did not bring me any joy.

My second experiment was with a local dish, the ones they served in my hometown were full of taste and joy. I thought I had found the answer to my question, the thing that would reliably make me happy. That's until I moved to a different city and the dish they served there was terrible and not even close to the one I liked, thus putting an end to my reliable source of joy.

My third experiment was with shopping, I had this perception that shopping brings one joy. and it did bring me joy. That is until It stopped. The expensive shirts didn't take long before losing their importance.

My last experiment so far has been with my Gaming PC. It's one thing I love the most in this world, It's as powerful as I had the means to make it and I get shivers in my body telling it to my friends, that's how much I love it. While I love it, it's stopped being the constant source of joy.

What I've concluded from the experiments mentioned is that when you depend on objects or people to be your source of happiness, you are going to be let down and you are going to get tired. Every
external source of happiness has a limit.

So if you want to be happy:

* Stop trying to be happy
* Be your own best friend
* Stop comparing yourself

I know this post doesn't fit the usual theme of the blog, but I had to put it out there.
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Atom Linter v2 Released]]></title>
            <link>https://aneesiqbal.ai/2017-03-13-linter-v2-released</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2017-03-13-linter-v2-released</guid>
            <pubDate>Mon, 13 Mar 2017 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[
It has been almost two years since the v1.0 of the [`linter`][] package for Atom was released to the general public. Since then, we have come a long way. Linter is the second most downloaded Atom package right now with over 2.7 million downloads. Thank you for being a part of it 🙇.

Linter v2 has been in the oven for more than a year and I'm excited to announce it's release to you today.

## Separate UI package

Starting from v2, Linter has support for pluggable UI providers. The default UI has been moved to [`linter-ui-default`][]. This opens ways for users to swap out UIs for Linter at will.

## Linter Panel

The Linter Panel is now a table with sortable columns. You can configure it to represent the current file or the entire project.

![Linter UI Default Panel](https://cloud.githubusercontent.com/assets/4278113/23875411/29906274-085b-11e7-88f9-a1c05a18d7eb.gif)

## Linter Status

The Linter Status, after much feedback, now includes three separate counts for `Error`s, `Warning`s and `Info`s. You can configure it to toggle the panel or jump to the error of the specific type when clicked. Just like the Linter Panel, you can configure Linter Status to represent the current file or the entire project.

<img alt="Linter UI Default Status" src="https://cloud.githubusercontent.com/assets/4278113/23875588/e4580544-085b-11e7-84c7-df6cc9725b0f.gif" />

## Busy Signal Integration

The new Linter UI now includes busy signal integration so you know which Linter provider is being excuted on which file.

<img alt="Linter UI Default Busy Signal" height="200" src="https://cloud.githubusercontent.com/assets/4278113/23875763/5c738c6a-085c-11e7-8d72-5b73f9306650.gif" />

## Intentions Integration

Linter now fully integrates with the [`intentions`][] package. This allows providers to use `solutions` in v2 and `fix` in v1 to allow the users to fix the issue without leaving the comfort of their Atom Editor.

<img alt="Linter UI Default Intentions" src="https://cloud.githubusercontent.com/assets/4278113/23875866/cdd051fe-085c-11e7-81c9-89fa59456891.gif" />

## Toggling Linter Providers

Linter v2 now includes commands to toggle linter providers from the command pallete.

<img alt="Linter Toggle Providers" src="https://cloud.githubusercontent.com/assets/4278113/23630039/56e760a4-02db-11e7-9b9b-0d8321a4ac4c.gif" />

## Tooltip Enhancements

We all know how intrusive tooltips can become when they follow your keyboard, therefore in v2 We've added an option for them to follow your mouse. This provides a much more comfortable Linter experience.

<img alt="Linter UI Default following Mouse" src="https://cloud.githubusercontent.com/assets/4278113/23876163/ebec18ca-085d-11e7-9137-b7a2c6ff6a14.gif" />
<img alt="Linter UI Default Follows Keyboard" src="https://cloud.githubusercontent.com/assets/4278113/23876225/3f5d8a98-085e-11e7-8c4f-171b8aa46367.gif" />

## TreeView Decoration

Linter v2 now decorates your TreeView. This is especially useful when combined with Project-Scoped linters like [`flow-ide`][] as it gives you the status of your entire project in just one look.

<img alt="Linter UI Default Tree View" height="500" src="https://cloud.githubusercontent.com/assets/4278113/23876314/b29a88a8-085e-11e7-98ef-33e57fbf12c9.gif" />

## Upgrading to Linter v2

If you are a package maintainer, we've prepared [migration docs](https://github.com/steelbrain/linter/tree/master/docs#migration-guides) for you. They are not perfect but we're open to contributions!

## Closing Thoughts

You can see [Linter v2 in Action](https://www.youtube.com/watch?v=Ek7p49sf8Eo) in the demo video.

This release is really exciting for me. I want to thank [Landon Abney](https://github.com/Arcanemagus) for his continued involvement in the Linter Project and for maintaining dozens of repositories in the [AtomLinter](https://github.com/AtomLinter) org. Thanks to everyone who has ever contributed to the Linter Project, and the users for providing useful bug reports. Peace out 👋 ☮.


[`linter`]:https://atom.io/packages/linter
[`linter-ui-default`]:https://atom.io/packages/linter-ui-default
[`intentions`]:https://atom.io/packages/intentions
[`flow-ide`]:https://atom.io/packages/flow-ide
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Should I root my Android Phone?]]></title>
            <link>https://aneesiqbal.ai/2017-01-29-should-i-root-my-android-phone</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2017-01-29-should-i-root-my-android-phone</guid>
            <pubDate>Sun, 29 Jan 2017 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[Android is an operating system developed by Google, primarily for Mobile Phones. Android is based on the Linux kernel and inherits it's permissions structure. The operating system itself runs as the SuperUser or root and allows the user of the phone to perform tasks as a non-privileged one.

## Why do you have to root

The reason Android doesn't give root permissions to the user by default is because the power of root is limitless. Once an application is granted root access it could potentially read all of your saved passwords, credit cards and other sensitive information from any app in your mobile phone and could even compromise your Wifi passwords.

Furthermore it could do permanent damage to your operating system that you couldn't fix without a reinstall, resulting in data loss for you. Your OEMs are actually being responsible when they patch the vulnerabilities in your phone that allow you to get root access.

You could only fix your compromised mobile phone by reinstalling it's operating system and it's not something everybody can do. Even if you can do it, doesn't mean you won't accidentally brick your phone.

While rooting your phone will give you full power to your operating system, it will also void your warranty in most of the countries and will block you out from services like Android Pay, Samsung Pay and similar services.

## But I still want to root my phone

If you have really made up your mind, then be careful in how you distribute root permissions to applications. There are two main concerns about usage of root permissions

0. Which su binary you use
0. Which applications you grant root access to

If you are confused about the first one, remember that [SuperSU was bought by a chinese company][1] and one user even went as far to say [it was sending out weird internet traffic][1]. Remember, this is all of your privacy you are trusting your root management application with. Your root management application (that interacts directly with su binary) has full root access and manages prompts of other applications requesting root access so choose the one you trust the most. I personally find Phh superuser to be trust worthy.

Remember, there is no undo button with root. Once you give the wrong application root access it'll infect your phone quicker than you realize maybe without you even noticing it's happened. So be paranoid about giving applications root access.

## How about a custom firmware from XDA

Again, custom firmwares on XDA are modified in ways you might not even know. You don't know for sure that the Firmware you installed doesn't have spyware on it and won't send all of your passwords to some hacker's servers. Your best bet if you value your privacy is sticking with unrooted Stock Firmware.

## Closing thoughts

I am writing this all out because I voided my warranty and my sense of security thinking I'll get better customizability with a rooted Custom Firmware. It wasn't worth it, I couldn't get my Gear VR working on Lineage OS because it's Samsung only. and the latest LineageOS doesn't even have a Theme Editor so my root wasn't even worth the trouble. I knew what I was in for but I wasn't. I ended up restoring to stock with my knox counter tripped. Don't do what I did people.

[1]:https://www.androidpolice.com/2015/09/29/chainfire-transfers-ownership-of-supersu-to-ccmt-will-remain-involved-in-the-project-for-two-more-years/
[2]:https://www.reddit.com/r/AndroidQuestions/comments/55io5z/best_open_source_alternative_to_supersu/d8bgzvt/
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How I manage multiple Node.js versions]]></title>
            <link>https://aneesiqbal.ai/2016-07-19-how-i-manage-multiple-node-js-versions</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2016-07-19-how-i-manage-multiple-node-js-versions</guid>
            <pubDate>Tue, 19 Jul 2016 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[[Node.js][] is a lightweight Javascript runtime. It follows the [Semantic Versioning][semver] scheme so every major release has multiple API breaking changes. We change our Node.js version to make a certain app work or to upgrade to the latest version.

### Why I don't like Popular Options

After evaluating different popular options including NVM, Ubuntu Repos, Ubuntu PPAs, OSX Homebrew and OSX Macports I experienced a lot of issues with them including

0. They are OS specific
0. You cannot install specific Node.js versions
0. They can cause conflicts when more than one users try to run different versions of same global modules
0. You have to use `sudo` when installing global modules or linking local ones (except for homebrew)

Having to do `sudo` for npm is bad for a lot of reasons, for examples the directories/files it creates while running as sudo will be owned by root and you won't get to modify them afterwords.

### How I do it

I use the [n][] Node.js version manager by TJ Holowaychuk.
Here's it's pros and cons in comparison

#### Things awesome about n

0. Zero overhead ([unlike NVM][nvm-slow])
0. Works on any POSIX environment
0. Never asks for or requires sudo
0. Can download *any* Node.js version
0. Installs modules in `~/n` (configurable) so they are isolated per user

#### Possible downsides of n

0. Too easy if you are a [real programmer][xkcd-joke] 😁

### How you can too

You should uninstall the currently installed Node.js before anything else and then execute these in order

```
curl -L https://git.io/n-install | bash
# Press y in the prompt or configure the directory if you want
# Then restart your shell to update it's $PATH and be able to use n/node
exec $SHELL
```

That's it fellaws, now you have an isolated, working Node.js setup. If you went with the defaults you should have an `n` directory in your home directory.

### Basic Usage

n is a bash script so it's lightweight/minimal but still includes all the necessary features.

To upgrade to the latest version of Node.js do

```
n latest
```

or to install the lts version do

```
n lts
```

or say you want to download Node.js v8.9.4 do

```
n 8.9.4
```

If you want to access the list of installed versions and select between them, do

```
n
```

You can find more about [n][] in it's README.

**Note**: When switching between shells, remember to also include the line inserted by `n-install` in your shell's config file such as `~/.bash_profile`, `~/.bashrc` or `~/.zshrc`.

That's all for now folks, happy coding!

[n]:https://github.com/tj/n
[semver]:https://semver.org/
[Node.js]:https://nodejs.org/en/
[nvm-slow]:https://broken-by.me/lazy-load-nvm/
[xkcd-joke]:https://xkcd.com/378/
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How I debug Node.js]]></title>
            <link>https://aneesiqbal.ai/2016-04-15-how-i-debug-node-js</link>
            <guid isPermaLink="false">https://aneesiqbal.ai/2016-04-15-how-i-debug-node-js</guid>
            <pubDate>Fri, 15 Apr 2016 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[[Node.js][] is a server side runtime for Javascript apps. Being a server sided runtime, it doesn't have a GUI. Therefore it's abilities to provide an easy to use debugging interface are limited.


Update: Since this was written `--inspect` support has landed in Node.js. It's easier to use and doesn't require installing thirdparty tools.
You can find more about it in [Node.js debugging Docs][].

### Why I don't like Popular Options

There are several ways of debugging Node.js, here are few of the reasons why I don't like the most popular ones

#### Builtin CLI debugger

0. It doesn't have a GUI of course
0. It's slow and even hangs at times
0. You have to remember it's commands
0. Debugging complex problems is nearly impossible if not impossible

#### [node-inspector][]

0. It shows ES6 Maps and Sets as `null`
0. It shows objects as empty randomly
0. It is generally slow
0. It's *very* unstable

#### IDE Debuggers

0. The IDEs are costy
0. Each has their own UI
0. They are hard to setup
0. They lack advance features

### Electron to the rescue

[Electron][] is an open source project by GitHub, it is basically Chromium + Node.js. It has the best of both worlds, node's `require`, `global`s and all the other APIs along with Chromium Dev Tools.

I have written a small wrapper around Electron to allow for quick Node.js debugging. It's called [DeNode], short for Debug Node.
You can install it using npm

```sh
npm install -g denode
```

It registers itself as `denode` bin, it accepts an optional file path of the node module to execute on boot.

```sh
denode
denode ./index
denode `which browserify`
```

#### What's awesome about this?

0. You can click and expand on deep nested objects
0. You can profile your apps for memory leaks and CPU time
0. You can set breakpoints on the fly
0. You can update running code from dev tools
0. You can compile your files with babel and debug real source instead of gibberish using sourcemaps
0. Basically, all the awesomeness of Chromium Dev Tools

#### What's the side effect?

0. Not having the ability to execute it over a network or VM, theoretically you could do X forwarding but it would get too slow and painful


[Node.js]:https://nodejs.org/en/
[node-inspector]:https://www.npmjs.com/package/node-inspector
[Electron]:https://electron.atom.io/
[DeNode]:https://github.com/steelbrain/denode
[Node.js debugging Docs]:https://nodejs.org/en/docs/guides/debugging-getting-started/#enable-inspector
]]></content:encoded>
        </item>
    </channel>
</rss>