Mellow Clamour | flyingcakes Zola 2025-11-06T00:00:00+00:00 https://snehit.dev/atom.xml Weight Gain is a Condition, but losing is choice? Snehit Sah [email protected] http://snehit.dev 2025-11-06T00:00:00+00:00 2025-11-06T00:00:00+00:00 https://snehit.dev/posts/weight-loss-drugs/ <p><em>Disclaimer: NOTHING THAT I SAY IS MEDICAL ADVICE. ANY BIOLOGICAL REASONING PRESENTED IS A GROSS OVERSIMPLIFICATION.</em></p> <p>Recently opened the Tata 1mg app and was greeted with an advertorial banner:</p> <blockquote> <p>Obesity is not a choice. Its a condition.</p> </blockquote> <p>Or so the market <em>NOW</em> wants you to believe. CICO still holds: you retain the net calories you eat minus what you burn. Weight loss drugs want to plug the eating side - by reducing your appetite to binge.</p> <p>The results, observed as of new, are phenomenal. Findings report not just weight loss, but also inculcation of healthy eating habits in many users. The long term verdict is still awaited - will these weight loss drugs finally be a panacea for diet related health issues?</p> <p>But there is a narrative shift. Obesity is now not a choice. Its a blanket statement. As if your increased weight is something forced upon you by a higher power beyond our understanding.</p> <p>The traditional means of dealing with obesity was to cut down on food intake, exercise more; be in a calorie deficit. This works for many people. Because their lifestyle is truly messed up. Sedentary life, over reliance on fast food and a lack of physical activity. But what we're now telling them, is that such a lifestyle isn't a <em>choice</em> they made. Its a <em>condition</em> they suffer from. And here's a magic pill that can cure their condition.</p> <p>No shade, the magic pill is indeed almost magical. To begin with, GLP 1, a hormone (?) secreted when our stomach is full after eating, is what these pills provide. They signal your nervous system that your stomach is full, without you actually eating. Despite the simple mechanism, this apparently works great. Trials have had positive results. Market users have reported good progress. Where was GLP 1 found in nature? Saliva of Gila Monsters (a reptile). Kudos to whoever thought of analyzing the saliva of a reptile (I truly could never even go near a reptile, let alone think about analyzing stuff).</p> <p>As much respect I have for science, the marketing aspect totally kills it for me. You can't label genuine carelessness as a "condition". Such dissolution of individual autonomy in personal life isn't sensible. When you binge on a pizza, you know you're binging. Shit didn't happen to you magically by a red demon's grace. You don't stop looking at the problematic areas in your culture because now there's a bandaid available.</p> <p>And despite all, these drugs do work, which makes them all the more appealing. When seven of your friends get into their dream shape, thanks to a pill, why would you not want to? Then the advert sympathizes with your condition - it isn't your doing (!), don't blame yourself for your high BMI; don't be harsh on yourself; why force yourself to fight the "condition" alone? - GET YOUR PILLS TODAY!</p> <p>Yes, there are eating disorders and they need to be cured like a disorder is supposed to be cured. Regardless, labelling wrong lifestyle choices as "disorder" or "condition" will not work out in the long run.</p> <p>Many families presently do not cook food at home on regular basis. Bulk of diet is based on unhealthy food ordered from restaurants, fast food joints or takeaways. Whatever little cooking is done, is often reheating / frying frozen food. Worse, children are being forced into unhealthy junk food because their parents are too complacent to make healthy diet choices. If a 12 year old is overweight because of eating junk food five days a week, that's not a condition; it is gross negligence on part of his/her parents.</p> <p>This is a cultural shift which marked the last decade in India. A sudden boom in reliance on mass marketed over processed food becoming an integral part of culture.</p> <p>These are conscious choices individuals are making (and forcing). Hiding this behind label of a "condition" just to market weight loss drugs only normalizes the problematic behaviour - creating more patients, thus more users of these drugs. I repeat - this is not a condition. This is a calculated measure to ensure customers are lining up for these drugs.</p> <p>Before we talk about conditions one gets themselves into, let's first be open to discussing (and criticizing) the choices an individual makes.</p> <p>I still believe that many individuals do suffer from genuine disorders and new research into weight loss drugs is no less than a boon. My gripe with marketing does not extend to science itself.</p> Swadeshi Software Snehit Sah [email protected] http://snehit.dev 2025-09-27T00:00:00+00:00 2025-09-27T00:00:00+00:00 https://snehit.dev/posts/swadeshi-software/ <p>Ongoing tariff war has taught us Indians a lot about international trade - or so we think. Many tech workers may be affected by whatever is cooking in the western atmosphere. In this high ground, India has a new tech arrow - Swadeshi Software.</p> <p>We have long depended on software developed in the western world. And for a good reason. Software developed in India aren't all that common. It has also not been a matter of importance for most of us. If I want a software that lets me compile my ultra memory safe Rust code into a static binary, debating the country of origin of this said compiler is not even on the list of my considerations.</p> <p>However, this new consideration is being ingrained via moral suasion. A consideration for buying Indian goods isn't a twenty first century invention. As far as my personal knowledge dates, this was the major theme of the INC Session of 1906, where they adopted resolutions on Swadeshi and boycott of British goods. Bringing this consideration into the realm of software is indeed a recent brew up.</p> <p>The latest to enter this fora is Zoho. Its sudden call to fame largely orchestrated by our honorable minister of electronics and information technology - Shri Ashwini Vaishnaw. He posted a video on his official Twitter account, highlighting how he is switching to Zoho for the usual 'office' apps. In a subsequent presentation, he started off by mentioning how the slides were created using Zoho.</p> <p>This is a good step. Despite potential complains of favoritism, this act strengthens public belief that the government shall come forward to support tangible endeavours for developing software products in India. However, the question is larger - will such software stand the test of time?</p> <p>Indian companies wanting to ride this wave of Swadeshi love need to keep in mind that expectations will be high. Humans have a special space for familiarity, no matter how parasitic it may be. One unresolved complain from a Swadeshi app and users will happily switch back to the usual Microsoft ecosytem.</p> <p>Companies also must ensure that being Swadeshi isn't their only USP. There's ample examples of products which failed due to lack of innovation. Users won't buy the swadeshi dig for long. The question of innovation cannot be swept under the rug of Swadeshi. We don't want blank clones of existing applications. We need innovative software that present a competition to globally accepted software companies.</p> <p>The UPI ecosystem is a prime example of what good software should feel like. Another popular software, common among web developers, Postman has its origin in India.</p> <p>Government must also do its part in ensuring the economic ecosystem provides a smooth launch to software startups. Easing paperwork burden and compliance will go a long way.</p> <p>This will happen only if the foundations are strengthened. Let universities accept innovative software as valid replacement for certain courses. Award successful people with preferential access to contracts for initial time.</p> <p>Finally, Indian software growth should not be limited to companies selling Indian software. It should spill out to Indians making good software. There's a sharp difference. End of day, we want to produce "good software" not just "Indian software". A good user experience and necessary features are must even if your average user may not notice. Companies need to step ahead from features and address concerns of privacy, data harvesting, advertisement targetting etc. If these are not addressed, Indian software could very well end up being just an Indian data sink.</p> <p>As an example, Arattai chat application by Zoho currently doesn't support end to end encryption for texts by default. One must select "secret chat" feature to enable that. In 2025, I would expect a chat application to have E2EE as a basic feature.</p> <p>Self hosting culture is also nascent in India. There is a lack of applications that are developed for decentralized or federated usage. The very reason why Zoho email managed to be successful is because the email network is federated by design. Thats why I can use <em>[email protected]</em> as my email account and you can bring in your own server too. While companies want to hop onto interoperability bandwagon, they are reluctant to make their own products interoperable - again for an understandable reason. This however, isn't always a good option for users, especially the tech savvy ones, who look for technical specifications rather than the country of origin. Driving Indians to create not just Indian software, but <em>good software</em> will reap dividends.</p> <p>Going back to my initial statement - that I won't necessarily look for swadeshi compiler when compiling my Rust code - its necessary to understand (for the common man) that software isn't built from soil and metal. It is built incrementally, re-using vast amount of code written by people from diverse backgrounds. This holds especially true for open source software. Modern software which relies on re-using code via libraries / modules / packages / (whatever) are a melting pot of code that has been through many hands. If you think a piece of software is made in country X <em>(insert any country)</em> then you're mistaken.</p> <p>What we can call Indian is the business and economical aspect. We would love to make money in India AND be able to utilize that money to afford a better lifestyle. If that means making software in India, then absolutely. Alas, we don't have that ecosystem yet. People are busy navigating through regulatory hoops, doing the bare minimum and getting by with white labelling.</p> <p>Foundational research and development will need pumping money. Nobody is ready for that discussion yet. We won't build the next kernel or operating system in India without that. (We do have BOSS Linux, but its a Debian spin; not exactly Swadeshi in my terminology)</p> <p>While policy is important in this journey, there's a need to acknowledge that the success of western software giants is in a good part also attributed to the technical minds (lot of which are Indian immigrants). Things made in India will follow when its viable to do so and sufficiently rewards the right people.</p> A new bike (Riverside 120) Snehit Sah [email protected] http://snehit.dev 2025-08-30T00:00:00+00:00 2025-08-30T00:00:00+00:00 https://snehit.dev/posts/a-new-bike/ <p>I recently got a new bike. The purpose is to reach my office and the market quickly.</p> <p>My workplace, is barely any distance from my current flat. Its the building adjacent and an 8 minute walk. So I don't really <em>need</em> a bike for this tiny commute.</p> <p>For buying groceries though, its a totally different story. Getting my evening groceries on foot can take 30-45 minutes. Going to the supermarket can take nearly an hour for my round trip.</p> <p>And on other days, I just want to be able to go out biking because I like the activity Back during university days, I've spent a lot of time biking around Lutyen's Delhi and the diplomatic enclave.</p> <p>So, I went out to the nearby Decathlon store and checked out my options. I wanted to keep everything under 20k. Considering the value I'd get out of my bike, this seemed a reasonable limit for me.</p> <p>There were Rockrider bikes in the range. However, they were MTB form factor. I'll be riding on normal noads. All choices boiled down to 2 options: Riverside 120 and Riverside 500.</p> <p>The RS500 was a good machine by itself. 1x9 gearing, disc brakes, front suspension and hybrid form factor. But the price step up from RS120 was too much for the value I'd be getting out of it. So, considering my use cases, I got the RS120. Delivery took 2 days. With the basic accessories and home delivery, it costed just under 14.5k. Pretty decent for my needs.</p> <p>It reached me on Sunday. On Monday morning, I decided to reach my office on these two wheels. Lady luck was not on my side that day, because the bike skid right under my residential block and I totally scratched away my elbow.</p> <p>Instead of reaching my office on two wheels, I reached the hospital casualty in an auto rickshaw. Got dressing done and took another auto to my office.</p> <p>Crazy start to a new commuter.</p> <p>What had happened was that the pavement from my parking to road has a fair bit of incline. It had lot of moss growing on it due to monsoon. My cycle skid on that and hit one of the unaligned sewer lids, that sent me off flying.</p> <p>The brake handles were broken and something in the mechanics got jammed. I still don't know <em>why</em> the brake would get locked on such a fall, but they did. I took the bike back to Decathlon that evening and dropped for repair.</p> <p>They took three days to deliver the cycle back to me. While the service didn't cost me, transporting the cycle took another 1k out of my wallet. In hindsight, it need not have costed that much just for replacing a brake handle. Regardless, I believed it to be reasonable to get it fixed from the official store since the bike was basically brand new.</p> <p>Initial hiccups aside, I finally could ride my new bike. I made sure I don't fall over. Pretty sure my muscle memory was junked up, because my last bike was an entry level MTB with wider tyres. RS120 has much thinner tyres and it doesn't hesitate while gaining speed. It could take you few days to adjust to different tyres as a newbie.</p> <p>Shifting gears isn't perfect. Its realiable and smooth. But there's a very noticeable lag and you'll feel inertia when moving into a different gear. In rare cases, the gears did not shift. But thats so rare, I'd blame myself for not pressing the shifter hard enough.</p> <p>The bike stands just over 14kg, so its technically not a light machine. Going up inclines isn't as easy as I would like. The blame stands partly with my chicken legs; I got some self improvement pending. Thighs don't hurt while biking on plain roads, assuming you're in the right gear.</p> <p>I used the bike for my evening market sessions. Its pretty reliable for the purpose. I carry an old backpack to keep items. Attaching a pannier bag wasn't economical for me, considering I won't be lugging any heavy weights. Usually some fruits and a pack of milk.</p> <p>And then rain gods woke up and I could no longer take out my bike. It currently is missing in action, waiting for the weather to improve. Hopefully, I'll be able to get back on wheels by mid September. Might post an update later.</p> War of 1984 Snehit Sah [email protected] http://snehit.dev 2025-05-07T00:00:00+00:00 2025-05-07T00:00:00+00:00 https://snehit.dev/drafts/war-of-1984/ <h2 id="who-is-the-enemy">Who is the enemy?</h2> <p>Oceania, Eurasia and Eastasia were at a perpetual war. This was no ordinary war. It was going on for as long as <em>anyone</em> could remember. Maybe at least thirty years? Winston vaguely recalled that the war started somewhere in 1950s and the present year being 1984, a big chunk of the population had grown up without seeing a war free world.</p> <p>The Atomic Wars broke out in late 1940s, just after World War II. Standing against nuclear giants, the smaller countries had no chance of surviving. The ones who made out, did so via the path of totalitariansm - breaking and merging into three superstates: Oceania, Eurasia and Eastasia.</p> <p>Oceania was allied with Eastasia and together they fought against Eurasia (Russia + Europe).However, in the 60s, Ocenia switched allegiance - making peace with Eurasia and together fighting against Eastasia.</p> <p>Winston recalled, sometime during his adulthood, in the 70s, Oceania again changed sides and allied with Eastasia, fighting against Eurasia.</p> <p>How much of this is actually true? One can't know. When The Party said, Ocenia was at war with Eurasia, they meant, <em>Oceania had ALWAYS been at war with Eurasia.</em> This is no sudden reversal, but rather an accepted way of rewriting records overnight.</p> <p>The reality existed only in your head. And you'd wonder, how real the story in your head is, if there are absolutely no records to back that up?</p> <p>It was the Perpetual War. Nobody knew since when it was happening or against whom. Nobody knew if it was even happening or not. The Ministry of Truth ensured that no truth exists. All historical records were subject to revision.</p> <p>The only fact public knew is what The Party currently told them: that Oceania was at war with Eurasia and had always been at war with Eurasia. This "fact" could change anytime, retrospectively.</p> <p>The only way to live with this Perpetual War was to make peace with it, aptly reflected in The Party's slogan, <em>"War is Peace"</em>.</p> <h2 id="economic-functionalism">Economic functionalism</h2> <p>The Party knew a superstate won't survive for long. Humans are easy to divide. But they knew, citizens could remain united as long as everyone had a common enemy to hate.</p> <p>Thus came the wars and hate week. It unified Oceania's population against an external enemy. Not only that, it justified The Party's totalitarian control and oppression.</p> <p>Economy becomes a tool to gear this war. Which patriot would care about their luxuries when soldiers are dying protecting their nation? Goldstein's text explained, that primary aim of modern warfare is to use up products of machine without raising general standard of living. Factories churned out weapons instead of consumer goods, ensuring shortages. A permanent crisis born out of this process forced citizens to accept poverty and substandard living as necessary sacrifice. The least a civilian can contribute to the sovereignty of his nation.</p> <p>Brand names like Victory Gin, Victory Coffee, Victory Towers etc mocked realities of poverties. Artificial scarcities prevented any comfort that might spark dissatisfaction or a demand for better governance.</p> <p>With such a focus on war, The Party channeled all public dissent and dissatisfaction away from itself, towards a common enemy.....</p> <h2 id="forgetfulness-as-a-weapon">Forgetfulness as a weapon</h2> <p>....a common enemy nobody cared about. The Party could change the enemy from Eurasia to Eastasia mid Hate Week and public cleanly diverted their hate to the new enemy.</p> <p>Syme noted, <em>"Who controls the past, controls the future."</em> This was no ordinary observation. Rather this was the core of Party's narrative machine. By constant erasure of history, citizens were forced to accept contradictions. Critical thinking is a crime. Doublethink could get you to the Thought Police. Accept the new reality, retrospectively and ensure your dependence on Party's narrative.</p> <p>Among others, this process was highlighted in the way Party constantly changed its enemies. It was no longer a question of identifying the external enemy. It was a matter of identifying the internal individuals who could not accept the contradictions in real life. Thought Police did their deed to them.</p> <p>Doublethink, i.e. holding contrary beliefs simultaneously, was a constant theme in all Party actions. Enemy got changed all of sudden. Victory got announced amid defeat. Chocolate rations claimed to be increased despite being lowered.</p> <p>Winston in his diary noted that The Party could thrust its hand into the past and say of this or that event, 'it never happened'.</p> <h2 id="illusion-of-war">Illusion of War</h2> <p>The war had blurred line between reality and propaganda. Where is the combat happening? Airstrip One? Where <em>is</em> Airstrip One?</p> <p>With no way to know if the war was even happening, one could say that it too, existed only in people's heads. Does it make sense in a world where people's are supposed to not trust their own thoughts?</p> <p>To get around this, The Party ensured the <em>effects</em> of war were always visible, but not the battle itself. One could always see around them damaged buildings, air raid sirens, shortages, defence movement. But never the battle.</p> <p>The battle was not supposed to be perceived by public intellect. It was to be perceived through lens of Party's narrative. A government speaker could change identity of enemy on the fly during a public rally - posters, telescreen images of Eurasia get torn down and replaced with Eastasia and leader switched war propaganda mid sentence. No individual bats an eyelid.</p> <p>Did the war actually happen? Julia dismissed frontline reports as fake. Rocket bombs, which were claimed to be dropped by enemy, might have been dropped by Oceania itself to sustain public fear, pushing citizens to cling to Big Brother for protection.</p> <p>Even if the war happened, the powers were not hurting each other. It was a meaningless joust wasting only lives and resources on both sides. The pointless cycle of state rivalries benefitted nobody except the Party. And it hurted everyone in the society. Even thirty years of war later, nothing was resolved.</p> <p>If anyone was winning (or losing) in the war, it should have ended. Instead, there continued a cyclical capture and loss of regions. Goldstein described how none of the three powers could truly conquer one another and thus fought only to seize tiny territories rich in minerals or cheap labour. These places provided a bottomless reserve of resources to produce weapons.</p> <p>However, even if these contested regions didn't exist, the structure of world society and self maintainance would be no different.</p> <p>The war could very well be futile, existing solely to maintain the status quo. But The Party wants us to believe war to be a real threat. We must believe so.</p> <h2 id="ordinary-man-s-tale">Ordinary man's tale</h2> <p>War served an important economic function for the party. War was their 'get out of jail' free pass. While the Ministry of Truth ensured there were no economic failures, by rewriting records, the effects of these failures were borne by public. War was the tool to justify these effects.</p> <p>The Party also shields public against any information coming form outside Oceania. Party described the world beyond Oceania's shores as a bare, hungry and dilapidated place, in a manner to put public into an illusion that despite their hardships, they are in a better situation than others.</p> <p>Ordinary men are kept exhausted and distracted. Daily life is dominated by work and queues. The little time remaining which one's brain might use to think is claimed by the Party for their various rituals, like the daily Two Minutes Hate, Hate Week, indoctrination lectures, group exercises, compulsory daily redaings from Party literature, morning 'Physical Jerks' and of course, public hangings and executions normalizing violence.</p> <h2 id="the-war-today">The war today</h2> <p>1984 aside, we are fightings wars that we don't aim to win. The 'war on drugs' or the 'battle against XYZ disease' hasn't ever led us to a conclusion. It frames struggles to unite populations and makes us used to those struggles. It has at best, made the concerned population temporarily satisfied, giving them hope for a daybreak that might never come.</p> <p>More deeply, Orwell warned that endless war can be used to manipulate and control society. There are wars we are fighting only in our figment of imagination, with no information on the real ground status.</p> Valentine's At Connaught Snehit Sah [email protected] http://snehit.dev 2025-01-15T00:00:00+00:00 2025-01-15T00:00:00+00:00 https://snehit.dev/posts/snapshots/valentine-at-connaught/ <p>We told others that we'd be out for Valentine's. No, it wasn't a date. There was none. We both were supposed to be at our respective homes, sipping away tea at five o'clock.</p> <p>We had told others. Which was a good excuse for me to pop up at Connaught Place. I didn't live far away from Connaught Place. It was convenient to pop in at Connaught Place or adjoining areas on my bicycle at any bright hour of the day.</p> <p>I didn't wait for the evening, otherwise it'd be cold by the time I return. It was more of a late afternoon vibe, when I dusted my bicycle, kept in my steel water bottle and pedalled on.</p> <p>I take Janpath to reach Connaught Place. There are other lanes too, which will lead me to the epicenter, but Janpath is both, close to my side and convenient. More so, Janpath houses some other things I love passing beside from. The Western Court, Windsor Place, Sovereign, HC Mathur Lane, Kartavya Path, National Archives, Ministry of External Affairs office and not to forget, The National Museum.</p> <p>She was not there. Obviously. She doesn't live nearby and as I said, there was no date planned. I took out my phone, clicked a pic and circled the place on my bicycle itself. It was well enough a date. Despite not being there, both of us secretly wanting to be there.</p> <p><img src="/images/snapshots/valentine_connaught.jpg" alt="" /></p> <p>I clicked the picture at exactly 1717h. It was sent to her soon after.</p> <p>Later when we started going out, we frankly forgot about Connought Place. Maybe because the place wasn't an important bit for either of us at the moment. But Janpath was lucky to have been remembered an year and half later.</p> <p>I took my cycle and headed towards Shivaji Stadium. Its just two crossings away. My journey then took me to Mandir Marg and then back to home. A fruitful day.</p> Sabrimala Snehit Sah [email protected] http://snehit.dev 2025-01-10T00:00:00+00:00 2025-01-10T00:00:00+00:00 https://snehit.dev/posts/snapshots/sabrimala/ <p>For most of us, we first experienced "lockdown" during C-19. Many might've known the word beforehand, but the feeling of living in a lockdown was new for most of us. I however, experienced the first lockdown around a year before C-19 struck.</p> <p>Earlier that day, when we stepped into Trivandrum, our driver greeted us with a wide smile. We quickly loaded our luggage into an old Toyata and reached our guest house. It was a cozy guest house, surrounded by a lot of trees and peaceful vibe.</p> <p>But something was not right with the elders. Turned out, there was no cook in the guest house. We tried ordering food online, but failed because apparently, there was a lockdown.</p> <p>Sabrimala.</p> <p>Our area was under local lockdown because the Sabrimala issue had gained a lot of steam. Less then a week ago, women in the state had made the fourth-largest human chain ever, in demand for gender equality. There was fear of issue escalating into an uncivilized form so isolated areas were observing local lockdowns in order to restrict non-essential movement.</p> <hr> <p>There we were. No meals, no major snack, stuck in a guest house with no nearby hotel accepting new check-ins. We satisfied ourself with whatever packed snacks packets we had (not much).</p> <p>In the evening, my friend (who's family came along with us) and I went out on an indefinite walk. We decided, we'll walk further down the road, for as long as it took us to find something worth eating. I put on my slippers instead of shoes, thinking it won't be a long walk. Wrong decision.</p> <p>The sun was shining rather bright that day. Perfect for a late afternoon walk in winter. There was solace in the winds, not laden with sounds of vehicles. We seemed to be the only ones out in the empty locality. Once every few minutes, we managed to spot a local out on the road, but they were just locals. No vehicles or outsiders to be seen far and wide.</p> <p>We first went past a large groove, with what I presumed were coconut trees. More than just majestic, it felt like an entry to a peaceful haven, where away from the world you could hear nothing but the rustling sound of leaves and the birds who called that place home. But we decided coconut isn't something we could fill out stomachs with. So we went on.</p> <p>We walked a reasonably long time. A few times, I contemplated calling it a day and returing to our guest house. After all, who wants to be out alone in a new state where there's a lockdown imposed? Other times, my friend contemplated giving up and returning. However, we never thought of it at the same time, thus could never reach a consensus to return. So we trodded further.</p> <p>I think we had reached a major crossing. There were (closed) shops around us. How bad I wished for at least one of them to be open. A few steps further, at a trisection, we spotted a policeman on a chair, drinking tea. Who gave this person hot tea in midst of a lockdown? No wonder, the shop just beside him was open and it seemed to be open just for his pleasure.</p> <p>He looked at us with a slight eye of suspiscion. We pretended to be regular people looking for an open shop. We went to the shop and realized, we simply can't act. There was a language barrier.</p> <p>The shop was run by an old lady. The shop itself was very tiny and modest. She understood we were tourists. She removed the wooden plank at entry of her shop and let us come inside. With barely enough place for 3 people, we quickly picked up the stuff we wanted - mostly biscuits - and laid it out on the counter neatly, along with a banknote. She did the math and handed us the change along with the biscuits.</p> <p>I was young back then and considered Oreo to be an acceptable idea of food. Thus, our search for the day was called completed and we returned carrying a poly bag with biscuits.</p> <p>On the way back, we again stopped at the groove. It was beautiful; indeed, God's own country.</p> <hr> <p>Oreo wasn't an acceptable meal menu for our parents however.</p> <p>Later that evening, we managed to get the morning driver to take us out somewhere. He wasn't hopeful of finding a decent place to eat at. And indeed, he was right. No restaurants were open. Hotels were not accepting any guests.</p> <p>After much driving, we stopped at a roadside dhaba which even in this lockdown was bustling with energy. It seemed to have expanded and with the large shed, it felt more of an open air restaurant. We grabbed a table, but when it came to ordering, we stumbled upon the classic roadblock: language barrier. Again, the dhaba owner was very polite and welcoming. He let us come near the cooking area and showed us the stuff that was available. We pointed at whatever we wanted to eat, which he then transferred into our plates. And thus, we had what I will call a hearty meal.</p> <p>Long after I left Kerala, I kept wondering about how it was near magical that amid an official order to lock the area down, there were people, willing to feed even a stranger who's language they can't understand. Even if I may not remember those faces, I remember the people and the stories they gave me.</p> <hr> <p>6 years since that day, the Sabrimala issue still remains a case pending in the apex court. Despite me not having anything to do with the matter, it happens to be a reason that led us to have that experience which, most likely, nobody - even I - will ever have again.</p> Rethink AI communication streams Snehit Sah [email protected] http://snehit.dev 2025-01-04T00:00:00+00:00 2025-01-04T00:00:00+00:00 https://snehit.dev/posts/rethink-ai-communication/ <p>You would never think that I'll write about AI. But here we are.</p> <p>I recently tried out <a href="https://notebooklm.google.com/">NotebookLM</a>. While I don't use such tools in my daily workflow, it is fascinating to see how far we've come with AI. Mozilla recently launched its own AI assistant called <a href="https://orbitbymozilla.com/">Orbit</a>. It is geared towards summarizing web content.</p> <p>On the surface level, I wonder why there are so many AI tools, geared just towards simplifying slop created by humans. Innumerous tools that serve the sole purpose of summarizing content.</p> <p>But on a deeper level, I was questioning whether the said slop is actually created by humans. For one, we know that many websites are now using AI to automate writing of blog posts, articles, technical documents etc. There are AI tools that even create videos which eventually end up on YouTube. Even if the video is not entirely AI generated, the video often is created with a lot of inputs from an LLM: from the general script to dialogues, LLM are doing a lot for YouTube creators these days.</p> <p>We're at a situation where AI is creating content and AI is consuming content. We, who pretend to be the consumer, are actually consuming the AI output, not the actual content itself. Take for example NotebookLM giving summary of a YouTube video. It is an AI tool, giving summary for you to easily digest, while not requiring you to watch the video in its entirety. Its possible, the video itself might've been composed and generated by an AI tool. In the near future, I predict this to be the norm rather than a mere possibility.</p> <p>So what are the ends of the data? It is generated by AI and consumed by AI. In that case, is a YouTube video (precisely, the transcript) or a web blog a good communication medium between the two AI systems?</p> <p><img src="/images/ai-video-consume.png" alt="AI creates, AI consumes" /></p> <p>Application to application interaction has long been done via the concept of various Application Programming Interfaces (API). For example, web servers typically interact via REST APIs. In our case, two AI tools are interacting via a video format. Not exactly video yet, since NotebookLM uses transcripts (which is plaintext). But I'm pretty sure we'll soon have (or already have) a tool which can parse out information from a video.</p> <p>In such a scenario, someone really ought to be working on a system for interoperability between different AI tools. A common data exchange format. Or a protocol or whatever. Extracting information from a medium meant for humans is usually not the most effective for computers.</p> <p>I don't know where I am going with this one, but the fact that most of the internet is soon going to be bots is slightly concerning. Meta just now showed us how it wants social media to have fake bot profiles, sanctioned by Meta. The idea <a href="https://www.theverge.com/2025/1/3/24334946/meta-ai-profiles-instagram-facebook-bots">didn't get a good reception</a>. But who knows, in the near future, it might be a commonplace to interact with bots on the social media. In the same backdrop, the <a href="https://en.wikipedia.org/wiki/Dead_Internet_theory">Dead Internet Theory</a> comes to mind.</p> <p>With the huge amount of data that will run back and forth on the internet, wasting bandwidth communicating in a non-ideal format isn't a long term solution.</p> Clean Slate Snehit Sah [email protected] http://snehit.dev 2024-12-31T00:00:00+00:00 2024-12-31T00:00:00+00:00 https://snehit.dev/posts/snapshots/clean-slate/ <p>I factory resetted my phone 2 days back. I forgot to save the encryption password for WhatsApp backup, meaning I can't restore them now.</p> <p>Whats funny is that WhatsApp is among the most <em>insecure</em> platforms to text on. There's no point "encrypting" it. End to end encrypted, huh? What are the ends? For one, WhatsApp doesn't even encrypt media (which is where a lot of sensitive stuff is likely to be found). Only texts are encrypted. And texts might be less sensitive. More attached.</p> <p>I've lost near four years of texts with my family. I've lost the little things I shared and the little reactions I got. I've lost texts from the time I gently flirted with my lady and we came closer.</p> <p>As I said, WhatsApp local backups don't encrypt media. Thus, they're backed up and available on my laptop. So not everything is lost. Its just the texts that are inaccessible.</p> <p>Maybe, a clean slate. To start the new year. To look forward and write stories again. Texts aren't the end of this world. All memories lie etched in my mind and heart. And from these memories, shall rise the new future.</p> <p>Let this year be not for the resolutions I make, but the ones I fulfill. A new year. To start on a clean slate.</p> <p><em>welcome to 2025</em></p> Kenil Worth Snehit Sah [email protected] http://snehit.dev 2024-12-30T00:00:00+00:00 2024-12-30T00:00:00+00:00 https://snehit.dev/posts/snapshots/kenilworth/ <p>It was a police guest house. It was also the first time I used a razor to get beard off of my face.</p> <p><img src="/images/snapshots/kenilworth-guest-house.jpg" alt="" /></p> <p>In the March of 2023, I for the first time visited Darjeeling. It wasn't my type of place honestly. Bit more crowded than what I'd have preferred as a retreat. Not to mention. I usually am at odds with winter.</p> <p>But something was different that time. It was the newly blossoming thing in my chest. The waterfalls seemed to have a bit more shine. The air was fragrant and there was a newfound joy in buying Bisleri bottles. Even the crowded places, which I usually don't go well along with, seemed reasonable to me. After all, why should a couple not visit this place? I was wanting to have her along too here.</p> <hr> <p>On my first evening there, I was out in the local market. I didn't like the street food there. Although, I did spot a Mio Amore and stuffed myself with sugars.</p> <p><img src="/images/snapshots/kenilworth-mioamore.jpg" alt="" /></p> <p>The next day, I woke up and looking in the mirror I realised I had crossed that threshold where my beard would be acceptable to look at. I had my trimmer, but not the charger. Hearing the sound of trimmer motor, I could conclude very well that it won't last a full trim.</p> <p>I got a disposable razor from a nearby store and did the deed. Running a razor on my face for the first time. Seeing mildly dense beard come off of my face all of a sudden, like a dirty carpet being taken off after an event; it felt like a shedding of what I once was.</p> <p>I think I found myself cute. Because after I dressed up and looked in the mirror, I instinctively took out the phone, clicked a selfie and sent it to her.</p> <hr> <p>She mentions a lot about Buddhism. She studies about it. I never studied about Buddhism, but I've always found peace at Buddhist temples.</p> <p>I just happened to visit a Buddhist temple later that day.</p> <p><img src="/images/snapshots/kenilworth-shrine.jpg" alt="" /></p> <p>We went back to Kenil Worth; our last evening there. At the break of dawn next day, we set out for a new destination.</p> <hr> <p>I recently got the news that Kenil Worth guest house has permanently shut down. I'm much over a thousand miles away from Kenil Worth at the moment; can't verify if the news is true. Regardless, it's likely that things won't be the same when I return to that place.</p> <p>As with most things, I wouldn't say Kenil Worth was extraordinary. But the feeling I had in my heart was special. She and I used to make list of places we'll visit. Kenil Worth happened to be the first tourist place I visited after we had started making the list and I had added it to the list.</p> Using FUSE to write your filesystem on Linux Snehit Sah [email protected] http://snehit.dev 2024-11-01T00:00:00+00:00 2024-11-01T00:00:00+00:00 https://snehit.dev/fuse-talk-11-2024/ <h2 id="introduction">Introduction</h2> <p>FUSE is an interface that allows users to implement filesystems without needing to touch the bulky kernel code. While we might have heard about ext4 or btrfs, we too can develop our own filesystems!</p> <p>Get the slides <a href="https://files.snehit.dev/FUSE_Talk_Slides.pdf">here</a></p> <h2 id="about-fuse">About FUSE</h2> <p>FUSE = <strong>F</strong>ilesystem in <strong>USE</strong>rspace</p> <ul> <li>filesystem implementation runs in userspace <ul> <li>implementation written in a language of user's choice (eg. Python)</li> <li>implementation runs as a normal script or application</li> </ul> </li> <li>FUSE module provides a bridge from filesystem implementation to kernel interface</li> </ul> <p>FUSE has 3 major components:</p> <ul> <li>kernel module <code>fuse.ko</code></li> <li>userspace library <code>libfuse</code></li> <li>a mount utility</li> </ul> <h2 id="fuse-support-on-your-system">FUSE support on your system</h2> <p>The relevant kernel module, <code>fuse.ko</code> is shipped since Linux version 2.6.14, so any FUSE based filesystem implementation can be assumed to work across virtually all Linux systems as of now.</p> <p>The presence of FUSE kernel module can be checked on any Linux system.</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>[lain@wired ~]$ lsmod | grep fuse </span><span>fuse 212992 5 </span></code></pre> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>[lain@wired ~]$ pkg-config --list-all | grep ^fuse </span><span>fuse3 fuse3 - Filesystem in Userspace </span><span>fuse fuse - Filesystem in Userspace </span></code></pre> <h2 id="how-does-a-virtual-filesysetm-with-fuse-work">How does a virtual filesysetm with FUSE work?</h2> <ul> <li>FUSE library knows about the basic list of operations on filesystems</li> <li>the implementation is expected to provide definition for these basic methods</li> <li>whenever system performs one of the filesystem operations, FUSE module refers the implementation code for knowing how to service request</li> </ul> <h2 id="why-userspace">Why userspace?</h2> <ul> <li>ability to utilize the userspace stack <ul> <li>python libraries</li> <li>interact with desktop environment</li> <li>interact with network resources</li> </ul> </li> <li>don't touch the kernel if not needed</li> </ul> <h2 id="where-is-fuse-being-utilized">Where is FUSE being utilized?</h2> <ul> <li><a href="https://github.com/tuxera/ntfs-3g">NTFS-3G</a> uses FUSE to mount and read NTFS drives on Linux, FreeBSD, macOS and other operating systems</li> <li><a href="https://github.com/rfjakob/gocryptfs">gocryptfs</a> provides an encrypted overlay filesystem</li> <li><a href="https://github.com/astrada/google-drive-ocamlfuse">google-drive-ocamlfuse</a> lets you mount your Google Drive onto a local folder and browse/edit files</li> <li><a href="https://en.wikipedia.org/wiki/WikipediaFS">WikipediaFS</a> let you view and exit MediaWiki articles from your local file browser and text editor</li> </ul> <h2 id="using-fuse-to-write-a-youtube-channel-browser">Using Fuse to write a YouTube channel browser</h2> <p>The main idea here is to return data from the YouTube API instead of our SQLite database. Once you decide upon the way this filesystem should function, you can proceed to implementing the relevant functions.</p> <p>The complete code is on GitHub: <a href="https://github.com/flyingcakes85/fuse-yt/">flyingcakes85/fuse-yt</a>.</p> <h3 id="how-would-this-filesystem-work">How would this filesystem work?</h3> <p>For our very simple demonstration, lets assume the follewing</p> <ul> <li>at the root, there shall be multiple directories</li> <li>each of these directories will have names corresponding to the id of the channel they should be connected to</li> <li>each directory should list videos from the corresponding channel</li> </ul> <p>As a rough guideline, we can chart the following process</p> <ul> <li>when user opens a directory, we can extract the channel id from the directory path</li> <li>this channel id is then used to fetch videos via the YouTube API</li> <li><code>readdir()</code> returns these videos</li> </ul> <h3 id="enumerating-channels">Enumerating channels</h3> <p>This is the simplest part. All you've to do is to yield a list of strings which match channel names.</p> <pre data-lang="py" style="background-color:#2b303b;color:#c0c5ce;" class="language-py "><code class="language-py" data-lang="py"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">readdir</span><span>(</span><span style="color:#bf616a;">self</span><span>, </span><span style="color:#bf616a;">path</span><span>: str, </span><span style="color:#bf616a;">_offset</span><span>: int): </span><span> contents = [&quot;</span><span style="color:#a3be8c;">.</span><span>&quot;, &quot;</span><span style="color:#a3be8c;">..</span><span>&quot;] </span><span> </span><span style="color:#b48ead;">if </span><span>path == &quot;</span><span style="color:#a3be8c;">/</span><span>&quot;: </span><span> contents.</span><span style="color:#bf616a;">extend</span><span>(</span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#bf616a;">_channel_list</span><span>()) </span><span> </span><span> </span><span style="color:#b48ead;">for </span><span>r </span><span style="color:#b48ead;">in </span><span>contents: </span><span> </span><span style="color:#b48ead;">yield </span><span>fuse.</span><span style="color:#bf616a;">Direntry</span><span>(r) </span></code></pre> <h3 id="listing-video-files-in-channel-folders">Listing video files in channel folders</h3> <p>We extend our earlier <code>readdir()</code> function to return "video files" if the path isn't at root. We append the names of videos to <code>content</code> array, which is finally returned by the function.</p> <pre data-lang="py" style="background-color:#2b303b;color:#c0c5ce;" class="language-py "><code class="language-py" data-lang="py"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">readdir</span><span>(</span><span style="color:#bf616a;">self</span><span>, </span><span style="color:#bf616a;">path</span><span>: str, </span><span style="color:#bf616a;">_offset</span><span>: int): </span><span> </span><span style="color:#65737e;"># --- snip --- </span><span> </span><span style="color:#b48ead;">else</span><span>: </span><span> channel_name = path.</span><span style="color:#bf616a;">split</span><span>(&quot;</span><span style="color:#a3be8c;">/</span><span>&quot;)[</span><span style="color:#d08770;">1</span><span>] </span><span> videos = </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#bf616a;">_get_videos</span><span>(channel_name) </span><span> </span><span style="color:#b48ead;">for </span><span>v </span><span style="color:#b48ead;">in </span><span>videos: </span><span> contents.</span><span style="color:#bf616a;">append</span><span>( </span><span> v[&quot;</span><span style="color:#a3be8c;">snippet</span><span>&quot;][&quot;</span><span style="color:#a3be8c;">resourceId</span><span>&quot;][&quot;</span><span style="color:#a3be8c;">videoId</span><span>&quot;] </span><span> + &quot;</span><span style="color:#a3be8c;">_</span><span>&quot; </span><span> + v[&quot;</span><span style="color:#a3be8c;">snippet</span><span>&quot;][&quot;</span><span style="color:#a3be8c;">title</span><span>&quot;].</span><span style="color:#bf616a;">replace</span><span>(&quot;</span><span style="color:#a3be8c;">/</span><span>&quot;, &quot; &quot;) </span><span> + &quot;</span><span style="color:#a3be8c;">.desktop</span><span>&quot; </span><span> ) </span><span> </span><span style="color:#65737e;"># --- snip --- </span></code></pre> <h3 id="but-do-we-download-the-videos">But do we download the videos?</h3> <p>Not really! It will be a huge wastage of bandwidth to download each video when opening the directory. Moreover, this will make filesystem operations very slow.</p> <p>Videos can be played via <code>mpv</code> by using <code>yt-dlp</code> as a provider</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">mpv</span><span> https://www.youtube.com/watch?v=dQw4w9WgXcQ </span></code></pre> <p>This can be shortened to</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">mpv</span><span> ytdl://dQw4w9WgXcQ </span></code></pre> <p>So, we could return "files", which are just shell scripts with the following content:</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#65737e;">#!/usr/bin/env bash </span><span style="color:#bf616a;">mpv</span><span> ytdl://$</span><span style="color:#bf616a;">VIDEO_ID </span></code></pre> <p>Sufficient?</p> <p><img src="/images/py-yt-shell-files.png" alt="" /></p> <p>Well, nope! While executing these scripts may play the corresponding video, but they're NOT resembling video files AT ALL!</p> <p>So how do you get icons to a file?</p> <h3 id="presenting-video-files-to-user">Presenting video files to user</h3> <p>You create what's called a <a href="https://specifications.freedesktop.org/desktop-entry-spec/latest/">desktop entry</a>. These a way to create shortcuts to commands and these files can specify their own icons too.</p> <p>Here's what a simple desktop entry for the above shell script should look like:</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>[Desktop Entry] </span><span> </span><span>Type=Application </span><span> </span><span>Name=Rick Astley - Never Gonna Give You Up (Official Music Video) </span><span>Exec=mpv --ytdl-raw-options=paths=/tmp ytdl://dQw4w9WgXcQ </span><span>Icon=/tmp/dQw4w9WgXcQ.jpg </span><span> </span><span>Comment= </span><span> </span><span>Categories=Video; </span><span>Keywords=youtube; </span><span> </span><span>NoDisplay=false </span></code></pre> <p>Now it looks much better</p> <p><img src="/images/py-yt-rick.png" alt="" /></p> <p>Finally, we use this as file contents for each video, replacing the video id and title everytime.</p> <p>Out <code>read()</code> function now extracts video name from path</p> <pre data-lang="py" style="background-color:#2b303b;color:#c0c5ce;" class="language-py "><code class="language-py" data-lang="py"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">read</span><span>(</span><span style="color:#bf616a;">self</span><span>, </span><span style="color:#bf616a;">path</span><span>: str, </span><span style="color:#bf616a;">_size</span><span>: int, </span><span style="color:#bf616a;">_offset</span><span>: int) -&gt; bytes: </span><span> </span><span style="color:#b48ead;">try</span><span>: </span><span> video_name = path.</span><span style="color:#bf616a;">split</span><span>(&quot;</span><span style="color:#a3be8c;">/</span><span>&quot;)[</span><span style="color:#d08770;">2</span><span>] </span><span> video_id = video_name[:</span><span style="color:#d08770;">11</span><span>] </span><span> file_contents = </span><span style="color:#b48ead;">f</span><span>&quot;&quot;&quot;</span><span style="color:#a3be8c;">[Desktop Entry] </span><span style="color:#a3be8c;"> </span><span style="color:#a3be8c;">Type=Application </span><span style="color:#a3be8c;"> </span><span style="color:#a3be8c;">Name=</span><span>{video_name[</span><span style="color:#d08770;">12</span><span>:-</span><span style="color:#d08770;">8</span><span>]} </span><span style="color:#a3be8c;">Exec=mpv --ytdl-raw-options=paths=/tmp ytdl://</span><span>{video_id} </span><span style="color:#a3be8c;">Icon=</span><span>{</span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#bf616a;">CACHE_FOLDER</span><span>}</span><span style="color:#a3be8c;">/</span><span>{video_id}</span><span style="color:#a3be8c;">.jpg </span><span style="color:#a3be8c;"> </span><span style="color:#a3be8c;">Comment= </span><span style="color:#a3be8c;"> </span><span style="color:#a3be8c;">Categories=Video; </span><span style="color:#a3be8c;">Keywords=youtube; </span><span style="color:#a3be8c;"> </span><span style="color:#a3be8c;">RunInTerminal=true </span><span style="color:#a3be8c;">NoDisplay=false </span><span>&quot;&quot;&quot; </span><span> </span><span style="color:#b48ead;">return </span><span style="color:#bf616a;">bytes</span><span>(file_contents, &quot;</span><span style="color:#a3be8c;">utf-8</span><span>&quot;) </span><span> </span><span style="color:#b48ead;">except </span><span>ValueError: </span><span> </span><span style="color:#b48ead;">return </span><span>-errno.</span><span style="color:#bf616a;">ENOENT </span></code></pre> <h3 id="adding-new-channels-i-e-directories">Adding new "channels" (i.e. directories)</h3> <p>By now, we have everything implemented that will fetch videos given the channel id. So, logically speaking, in order to add a new channel, all we need to do is to add that channel id to our array <code>CHANNEL_LIST</code>.</p> <p>We will need to implement two functions: <code>mkdir</code> and <code>rename</code>. While you can create a folder of your preferred name via <code>mkdir</code> command at the shell, many file explorers create folder with a default name and then rename it to your desired one. Thus, keeping in mind our use case (i.e. usability from file explorers), its important to implement both <code>mkdir</code> and <code>rename</code>.</p> <pre data-lang="py" style="background-color:#2b303b;color:#c0c5ce;" class="language-py "><code class="language-py" data-lang="py"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">mkdir</span><span>(</span><span style="color:#bf616a;">self</span><span>, </span><span style="color:#bf616a;">path</span><span>: str, </span><span style="color:#bf616a;">mode</span><span>: str): </span><span> parent_dir, new_channel = os.path.</span><span style="color:#bf616a;">split</span><span>(path) </span><span> </span><span> </span><span style="color:#65737e;"># sanity checks </span><span> </span><span style="color:#b48ead;">if </span><span>parent_dir != &quot;</span><span style="color:#a3be8c;">/</span><span>&quot;: </span><span> </span><span style="color:#b48ead;">return </span><span>-errno.</span><span style="color:#bf616a;">ENOENT </span><span> </span><span> </span><span style="color:#b48ead;">if </span><span>new_channel in </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#bf616a;">_channel_list</span><span>(): </span><span> </span><span style="color:#b48ead;">return </span><span>errno.</span><span style="color:#bf616a;">EEXIST </span><span> </span><span> </span><span style="color:#65737e;"># append to channel list </span><span> </span><span style="color:#bf616a;">self</span><span>.CHANNEL_LIST.</span><span style="color:#bf616a;">append</span><span>(new_channel) </span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">rename</span><span>(</span><span style="color:#bf616a;">self</span><span>, </span><span style="color:#bf616a;">pathfrom</span><span>: str, </span><span style="color:#bf616a;">pathto</span><span>: str): </span><span> parent_dir, old_name = os.path.</span><span style="color:#bf616a;">split</span><span>(pathfrom) </span><span> </span><span> </span><span style="color:#65737e;"># sanity checks </span><span> </span><span style="color:#b48ead;">if </span><span>parent_dir != &quot;</span><span style="color:#a3be8c;">/</span><span>&quot;: </span><span> </span><span style="color:#b48ead;">return </span><span>-errno.</span><span style="color:#bf616a;">ENOENT </span><span> </span><span> parent_dir, new_name = os.path.</span><span style="color:#bf616a;">split</span><span>(pathto) </span><span> </span><span> </span><span style="color:#b48ead;">if </span><span>parent_dir != &quot;</span><span style="color:#a3be8c;">/</span><span>&quot;: </span><span> </span><span style="color:#b48ead;">return </span><span>-errno.</span><span style="color:#bf616a;">ENOENT </span><span> </span><span> </span><span style="color:#65737e;"># rename </span><span> </span><span style="color:#b48ead;">for </span><span>i </span><span style="color:#b48ead;">in </span><span style="color:#96b5b4;">range</span><span>(</span><span style="color:#96b5b4;">len</span><span>(</span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#bf616a;">CHANNEL_LIST</span><span>)): </span><span> </span><span style="color:#b48ead;">if </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#bf616a;">CHANNEL_LIST</span><span>[i] == old_name: </span><span> </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#bf616a;">CHANNEL_LIST</span><span>[i] = new_name </span><span> </span><span style="color:#b48ead;">break </span><span> i = i + </span><span style="color:#d08770;">1 </span></code></pre> <p><img src="/images/channel_list_fuse.png" alt="" /></p> <p><img src="/images/video-list-fuse.png" alt="" /></p> Jamnagar House Snehit Sah [email protected] http://snehit.dev 2024-07-25T00:00:00+00:00 2024-07-25T00:00:00+00:00 https://snehit.dev/posts/jamnagar-house/ <p>The recent wedding news of Anant Ambani and Radhika Merchant made headlines across the country. Among other things, it brought in news the city of Jamnagar in Gujarat, where the pre wedding celebrations took place.</p> <p>That reminded me of the other Jamnagar I know of since a young age.</p> <p>On the Shahjahan Road in New Delhi, you find a modest entrance into a complex of single floor structures. These structures don't follow the Georgian architecture thats used in neighboring heritage of Connaught Place. What are these tiny structures looking straight out of history?</p> <h2 id="what-is-jamnagar-house">What is Jamnagar House?</h2> <p>Present day district of Jamnagar in Gujarat encapsulates the former state of Nawanagar. The rulers of this state used the title <strong>Jam Saheb</strong>.</p> <p>Random tidbit: The Ranji Trophy is named after Jam Saheb Ranjit Singh Ji, who was a famous cricket player at Cambridge.</p> <p><img src="/images/jamnagar-ranjitsingh.jpeg" alt="" /> <em>Jam Saheb Ranjit Singh</em></p> <p>The Nawanagar State survived for over four centuries, before merging with the newly independent state of India. The erstwhile ruler of Nawanagar, Digvijay Singh Ji signed Instrument of Accession to Dominion of India on the day of Indian independence on 15th August 1947. He also merged Nawanagar State into the United State of Kathiawar the next year and served as its Rajpramukh (governor) for 8 years until the position was abolished.</p> <p>Among the royal residencies of New Delhi, there is Jamnagar House - the residence of Jam Sahib of Nawanagar State.</p> <h2 id="jamnagar-house-photowalk">Jamnagar House: Photowalk</h2> <p>At the entrance, you can find a discolored board listing the offices presently operating from various barracks.</p> <p><img src="/images/jamnagar-entrance.jpg" alt="" /> <em>The listing is old and some of the listed offices no longer function out of Jamnagar House.</em></p> <p>Most barracks have substantial spacing between them. You can see these spaces being utilized as car parking for the employees that work here.</p> <p><img src="/images/jamnagar-road.jpg" alt="" /></p> <p><img src="/images/jamnagar-car-park.jpg" alt="" /></p> <p>For the longest time, you could never find a proper parking place due to the fact that this place was built at a time when you didn't have cars. There are more employees than the number of cars these open spaces can accomodate.</p> <p>However, recently, offices have started to be shifted out to newer buildings, thus leading Jamnagar House with less employees. That means, its easier to find a place to park your car!</p> <p>Barrack 12/1 houses the office of District Magistrate of New Delhi district. Barrack 13/1 houses office of Union Public Service Commission; the body conducting prestigious Civil Services Examination that lakhs of aspirants appear, hoping to occupy the handful seats to become a District Magistrate.</p> <p>As a side note, the present interview location for UPSC Civil Services is the Dholpur House, located just beside Jamnagar House. Dholpur house was the residence of Rana of Dholpur in Delhi and has its own rich history.</p> <p>The barracks carry arched windows till date. I wonder if the windows had more designs originally and were made minimalist during successive renovations.</p> <p><img src="/images/jamnagar-arch.jpg" alt="" /></p> <p>The barracks also follow the classical style of rooms being built around a central courtyard. As a result, you'll find open space on the inside too. This doubles up a good open place with sufficient privacy for officers to spend their breaks during winters.</p> <p><img src="/images/jamnagar-courtyard.jpg" alt="" /></p> <p>Barracks have a simple design from the outside. All of them are white and most have simple entrance gates.</p> <p><img src="/images/jamnagar-office.jpg" alt="" /></p> <p><img src="/images/jamnagar-office-door-1.jpg" alt="" /></p> <p><img src="/images/jamnagar-office-door-2.jpg" alt="" /></p> <p>Some entrances can be fancier than the rest.</p> <p><img src="/images/jamnagar-door-nalsa.jpg" alt="" /></p> <p><img src="/images/jamnagar-door-prasar-bharti.jpg" alt="" /></p> <p>The name plates too have variety. While some are pure metal plates, most are blue plastic plates. However, here and there, you can also spot rusted old style nameplates.</p> <p><img src="/images/jamnagar-plate-metal.jpg" alt="" /></p> <p><img src="/images/jamnagar-plate-blue.jpg" alt="" /></p> <p><img src="/images/jamnagar-plate-rust.jpg" alt="" /></p> <p>This area has been repurposed to house government houses. All the nameplates and parked cars give off the illusion of this place being a low cost office complex. However, if you try to look at the larger picture, you may see how the whole area could have worked just to serve one royal family. Different blocks housing different units of the service that comprises the royal experience. Kitchens, stables, barracks, courtyards etc are carefully hidden among the office colors Jamnagar House presently wears.</p> <p>The insides of these barracks are less amusing. They're laden with ceramic tiles, shelves, wires, air conditioners, computer tables and what not. Connecting corridors aren't maintained and often used to dump old furniture or other waste.</p> <p><img src="/images/jamnagar-corridor.jpg" alt="" /></p> <p>As boring as it may look, I can't stop thinking that years back, a royalty walked in these corridors. They looked out of these windows.</p> <h2 id="demolition">Demolition</h2> <p>Much has been lost to history. And more will be lost.</p> <p>Jamnagar House is no longer considered a usable area due to the weak structural integrity of old barracks. There are other concerns too: with only one floor, this area has very poor utilization of space.</p> <p>Offices are one by one being moved to newer towers which have many floors and can densely pack a lot more employees. Many offices at Jamnagar House are closed. Many barracks are vacant.</p> <p>As per the current proposals, it's slated for demolition once all offices are shifted out.</p> <p>As much inefficient as this complex may be, its never just the cement and brick that make it up. It has a history, a cultural significance, the remains of an important princely state.</p> <p>Keep wishing, nothing gets uprooted anymore.</p> <p>Walking down memory lane, you end up at the other end of Jamnagar House, which opens up on Man Singh Road. Across the roundabout is the Vice President's estate.</p> <p><img src="/images/jamnagar-mansingh.jpg" alt="" /></p> <p><img src="/images/jamnagar-board.jpg" alt="" /></p> Ice Cream Snehit Sah [email protected] http://snehit.dev 2024-03-25T00:00:00+00:00 2024-03-25T00:00:00+00:00 https://snehit.dev/posts/ice-cream/ <p>As a young primary grader, I didn't know that you could buy ice cream sticks from the store. I used to think, you need to eat ice creams and collect all the sticks. (if you do go down this way, please wash them before storing)</p> <img src="/images/ice-cream-stick.png" style="max-width:5.5in;" /> <p>Whenever the craft teacher at our school asked us to bring ice cream sticks for an activity, I used to look into my stash of used sticks and pick the ones which looked presentable.</p> <p>I grew up a bit and got to know you can buy these at the stationary anyways. No point storing the sticks.</p> <hr> <p>Eating ice cream wasn't an easy task back then. As much as I liked it, I could almost never handle the ice cream correctly without getting it on my clothes. It used to inevitably melt and drip on my t shirt.</p> <p>Worse, I didn't know that you're supposed to eat from both sides of the stick equally, otherwise one side gets heavier and falls down.</p> <p>As a result, I used to stick with ice cream cups as a child. It was then I discovered that for some mysterious reason, strawberry flavor was available only in cups, not sticks or cones. It tasted good, or atleast better than over-sweetened vanilla or chocolate.</p> <p>I was in 3rd class when I discovered that they sold cola flavored ice cream in my school canteen. Soon after, on my daily visit to the booth near my home, I saw I could buy cola flavored ice cream there too. That was the summer when I consumed ice cream the most.</p> <p>Cola flavor wasn't available in cups, so I had to learn how to use the stick. I faintly remember dropping my cola ice cream from the stick initially, but later learnt that I should eat from both sides of the stick alternatively. Its even better if I keep my other hand underneath the ice cream just in case the ice slab decides to slip off.</p> <p>And thus, I stopped relying on ice cream cups.</p> <hr> <p>It only took 2 summers for me to get bored of cola. I switched to having cones. Turned out, these were much easier to handle.</p> <p>I initially ate chocolate. Thats the only flavor they sold, wasn't it?</p> <p>Soon after, I discovered butterscotch. And thats when I truly discovered the taste I like. Or so I thought.</p> <p>I've been eating butterscotch ever since. Its the only flavor I prefer when I have to grab an ice cream. I'm not averse to other flavors, but I really won't feel having missed out on something if you were to have a chocobar without sharing with me.</p> <p>And yet, butterscotch doesn't exactly feel 100% the way I want.</p> <hr> <p>During Covid-19, we were too afraid to step outside the house. Social distancing, isolation and avoiding practically anything from outside the house - I didn't have ice cream that year.</p> <p>Being locked up inside the house with no access to outer world, I had faintly thought about a little scheme that could skyrocket ice cream sales.</p> <p>The (stupid) plan was that if companies started fortifying ice creams with vitamin D, it could generate a greater demand among consumers. There is widespread vitamin D deficiency among urban working class. During summers, most people dare not step outside their houses. In such a setting, vitamin D flavored ice cream could cool them down and also give a regular shot of vitamin D.</p> <p>That was maybe the wackiest ice cream idea I've ever had.</p> <hr> <p>In the summer of 2022, I caught the habit of drinking cold coffee. I had already spent the preceeding winter drinking chilled black coffee.</p> <p>I used to purchase bricks of vanilla ice cream and store them in the freezer. Used to scoop out whenever I needed ice cream for my cold coffee.</p> <p>An year later, in the summer of 2023, I was an intern at a company. They had a coffee machine in the cafeteria, but it was for hot coffee. Not cold.</p> <p>I decided I could mix and match. They used to stock Nescafe's chilled latte in their refrigerator. And they had these vanilla ice cream cups in their deep freeze.</p> <p><img src="/images/nescafe-cold-coffee.png" alt="" /></p> <p>I used to pour out the latte in a cup and scoop out ice cream into the same cup. And thus, I got my (makeshift) cold coffee with ice cream and I once again used these ice cream cups.</p> <p>Back to where we started?</p> <hr> <p>I haven't had much ice cream after that summer. It usually was a butterscotch cone shared with her.</p> <p>In a story I wrote during Covid lockdown, a young couple was at an ice cream parlour having their first ice cream together. The boy had no specific preference so the girl gets him strawberry ice cream.</p> <p>They were sitting beside the ice cream parlour on a wooden bench, when the girl lands a surprise kiss on the boy's cheek. There, the boy realizes that the ice cream flavor doesn't matter. Ice cream was just an excuse. What really matters is something else.</p> <blockquote> <p>We stopped at the ice cream parlor. <br><br> "Which one would you like to have?", I asked him. <br><br> "Whichever you have." <br><br> "Two strawberry cones, please!" <br><br> We sat on the wooden bench behind the ice cream parlor. The sun was setting, and I knew, this moment won't come ever again. <br><br> I leaned over to Miller's side and kissed him on the cheek.</p> </blockquote> <p>Like everything else I've had a past life with, I come to know what matters. Its <em>really</em> not butterscotch. Its the person who shares her warm and sweet kiss with me.</p> Finding Mandir On Evening Walk Snehit Sah [email protected] http://snehit.dev 2024-02-11T00:00:00+00:00 2024-02-11T00:00:00+00:00 https://snehit.dev/posts/finding-mandir-on-evening-walk/ <p>I live in a typical old locality of low rise buildings, built at distance from each other. What it ensures are abundant streets and back alleys to explore on my evening walks.</p> <p>I spotted a Ganesh idol beside a tree on a narrow street behind the main park. That led me to start noticing these idols much more frequently.</p> <p><img src="/images/1707662986471.jpg" alt="image1" /> <em><a href="https://files.snehit.dev/blog/1707662986471.jpg">See full size</a></em></p> <p>Walking down the street, its a reminder of the faith that has propelled our culture and civilization for thousands of years. The fact that I'm only a temporary tenant on this land. The land truly belongs only to the soul of that idol placed beside the tree.</p> <p>On my walk today, I spotted a new idol. Remains of the trees that were cut before this winter were now sheltering a small idol.</p> <p><img src="/images/1707662962608.jpg" alt="image2" /> <em><a href="https://files.snehit.dev/blog/1707662962608.jpg">See full size</a></em></p> <p>Its a fun exercise for me to keep noticing these. Little idols hidden in plain sight. Peepal trees with <em>kalava</em><sup class="footnote-reference"><a href="#kalava">1</a></sup> wound around them. Or, ends of the street with a little temple.</p> <p>On one of my evening previous evening walks, I spotted a cute little mandir attached to a garden's corner. An aesthetic purple color to the walls stood out againt the otherwise greenish environment. Three flower pots were kept on small cemented area outside. An old wooden table was kept at some distance for anyone to keep their belongings.</p> <p><img src="/images/1707662986501.jpg" alt="image3" /> <em><a href="https://files.snehit.dev/blog/1707662986501.jpg">See full size</a></em></p> <p>The street didn't lead anywhere in particular. This was the unused space between two buildings. Undoubtedly, an excellent use of space.</p> <p>Our culture has a very special intersection with faith. It makes me happy to see people practice their faith in such tiny ways, giving back this land to whom it belongs and reminding us of the origin out of this plastic world we live in.</p> <p>The only concern I had: Thousand years later, will the remains of this litte mandir be used to justify an inherently anti-cultural act? Will the remains of our faith be cause someone else's demolition?</p> <p>Suggested reading: <a href="https://snehit.dev/posts/demolition/">Demolition</a></p> <hr> <small> <h4>Footnotes</h4> <div class="footnote-definition" id="kalava"><sup class="footnote-definition-label">1</sup> <p>A red-yellow colored ritual thread associated with Hindu culture. The thread is normally tied on the wrist, but can also be tied around other items considered sacred, such as <em>kalasha</em> or the Peepal tree.</p> </div> </small> Progressive Vandalism By Indian Tech Community Snehit Sah [email protected] http://snehit.dev 2024-02-06T00:00:00+00:00 2024-02-06T00:00:00+00:00 https://snehit.dev/posts/progressive-vandalism-of-indian-tech-community/ <p><em>Disclaimer: I have no personal interest in bashing Indians. I'm from India too. For better or worse, I also happen to be from the same university as the instructor of the recently viral video about Git/GitHub.</em></p> <p><em>2nd Disclaimer: No, this is not racism. ~17% of world's population is Indian, so I understand that a proportional amount of BS I see on the internet would also come from India. Regardless, there only so far we can go by saying "we got a huge population". Issues need to be addressed.</em></p> <p>This post comes after I watched <a href="https://www.youtube.com/@ThePrimeTimeagen">The Primeagen</a>'s recent video about the Express GitHub repo spam. I appreciate his balanced take. Its indeed a good idea to not assume that there was malicious intent in the instructor or the students who followed the tutorial.</p> <p>Having been in open source before the vandalization started and seeing everything in the Indian context, its imperative that I'm not happy about the present state of affairs and choosing to finally write about it.</p> <h2 id="race-to-be-separate-from-competition">Race to be separate from competition</h2> <p>Due to the low opportunity vs job seeker ratio, its understood that the scene here is highly saturated. People want a different way - not necessarily short-cuts. They just want a path where they can breathe, have space and not feel lost in the crowd.</p> <p>Hype trains go very well in such a setting.</p> <p>It started with the FAANG hype, when these creators launched all sorts of courses for DSA (data structures and algorithms). We saw companies rise up whose primary offerings are DSA courses and interview preparation.</p> <p>Once the FAANG scene was sufficiently saturated, students again wanted a breath of fresh air. Creators shifted to hyping open source. It led to the GitHub repo spam we saw with Express (and the various instances in the past). If students are spamming one repo en masse after watching a specific video, it wouldn't be wrong to say that the instructor - even if unintentionally - made a mistake there. Google Summer of Code is saturated too, with students who have no idea about the philosophy of open source.</p> <p>The next stop for them is remote jobs. A certain YouTuber has spent enough time hyping remote jobs already. This is now followed by creators pushing out "roadmaps" to "cracking" remote jobs.</p> <h2 id="the-larger-signalling">The Larger Signalling</h2> <p>These creators spread their agenda over multiple fronts so that they can't be criticized easily. It played out very well with Primeagen, when he acknowledged that the YT video was primarily an educational video.</p> <p>Reality is that once you look at there creators' wider appeal, they aren't educators. They're peddlers of motivation, dreams and hype. I prefer calling them influencers. Their follower base is of a very specific kind - one that wants to be spoonfed and shown grand dreams. Influencers are well aware of this. These influencers intentionally targeted their content to such a group when they were building their following. Even when they push out an educational video, experience has taught us that it'll wreck something or the other.</p> <p><img src="/images/dream-peddler.png" alt="Dream Peddler" /></p> <p>This is an even more sensitive issue here, because a lot of students belong to under privileged background. They can be easily lured by these dreams. Learning will take a backseat. Primeagen too acknowledged the fact that had someone pitched open source to him back in the days, he'd have certainly jumped right in. (<a href="https://youtu.be/6ZWg9FIn_Bg?&amp;t=902">15:00</a>)</p> <p>If he can acknowledge and understand this fact, then why can't we expect Indian tech content creators to be more responsible? These creators literally grew up among Indian students and know the socio-economic situation very well. What merit do they have in pretending to be unaware of the damage they're causing? Of course, its their business. Only if they first sell dreams, they can later sell their courses.<sup class="footnote-reference"><a href="#courses">1</a></sup></p> <p>The signalling starts with them uploading videos saying how open source is the new secret to getting noticed and getting good jobs. They'll get FAANG employees onto their stream to talk about how open source gave them the breakthrough they needed. The video thumbnail will mention huge salary packages to lure needy students. Once they've convinced enough students that open source is indeed the magic syrup, they'll launch their courses.</p> <p>The Express repo spam wasn't a one off event. Its been happening every now and then in the past 3 years at the very least. This progressive vandalism has been affecting the genuine Indian contributors. Creators are very well aware of the damage they're causing. Pushing out sombre apology videos is of no use if they again resort to the same old tactic.</p> <p>I'm choosing to intentionally not name any channel. But as an example, just see this search result for yourself to realize the amount of signalling that goes on: <a href="https://www.youtube.com/results?search_query=open+source+to+job">open source to job - YouTube search</a>.</p> <h2 id="is-gatekeeping-the-solution">Is gatekeeping the solution?</h2> <p>In the past, I've been accused of gatekeeping by my peers because I often refuse to spoonfeed. My agenda always has been that a student should realize what motivates him and pursue that. Open source is just ONE of the many ways to be noticed. Just because an influencer said open source is the way, that doesn't mean every student should jump on to GitHub.</p> <p>I've stressed on the importance on realizing one's own interests.</p> <p>These influencers however know that they need a large group of students wanting the SAME THING. Only then the influencer can sell his ONE course to MANY people. So they need to hype certain things (eg. open source) to the point where they amass a large crowd wanting to learn the same thing. Its obviously turning the precious human capital into robotic monkeys. It IS a problem.</p> <p>Its distancing students from the essence of technology. Money is of course a big motivator and it should be. However, by dumbing down the students, these influencers aren't helping them earn money either.</p> <p>The solution is not gatekeeping. It is to empower students, to help them understand that there's a ton of ways to make their mark.</p> <p>Influencers are willingly failing at that. Its a net negative result. Doesn't benefit anyone except the influencer selling courses. In a previous post, I wrote about how the culture of "roadmaps" harm students. Read it here: <a href="https://snehit.dev/posts/roadmaps/">Tech Roadmap (to Industrial Age)</a></p> <h2 id="if-not-influencers-then-who">If not influencers, then who?</h2> <p>I used to be asked this question on rare occasions. Funny enough, seemed like students have never even used the YouTube search function and always relied on the Trending tab.</p> <p>There's way too many YT channels that teach tech. Some of them off the top of my head:</p> <ul> <li><a href="https://www.youtube.com/@TheCherno">The Cherno</a> - easy explanations for C++ concepts and some game development videos too</li> <li><a href="https://www.youtube.com/@freecodecamp">FreeCodeCamp</a> - Videos on a variety of programming topics from various creators</li> <li><a href="https://www.youtube.com/@ThePrimeTimeagen">ThePrimeTime</a> - Often discusses interesting technical topics on his streams</li> <li><a href="https://www.youtube.com/@HiteshChoudharydotcom">Hitesh Choudhary</a> - Short tutorials on wide variety of topics</li> <li><a href="https://www.youtube.com/@mitocw">MIT OCW</a> - lots of recorded lectures from MIT on a host of topics beyond just science</li> <li><em>practically any channel that focuses on teaching rather than peddling dreams</em></li> </ul> <hr> <h4>Footnotes</h4> <small> <div class="footnote-definition" id="courses"><sup class="footnote-definition-label">1</sup> <p>I'm not against courses. Neither am I against marketing. What I oppose is the rampant disregard to the effects of evil marketing being done by certain course creators.</p> </div> </small> Demolition Snehit Sah [email protected] http://snehit.dev 2024-01-22T00:00:00+00:00 2024-01-22T00:00:00+00:00 https://snehit.dev/posts/demolition/ <h2 id="stirrings-in-afghanistan-buddhism-there-and-here">Stirrings in Afghanistan: Buddhism there and here</h2> <p><em>15th August 2021</em></p> <p>Kabul was recaptured and someone returned to power in the Afghanistan region.</p> <p>That was when I took notice of Taliban. It wasn't surprising. Human civilizations have had a parallel power tussle. Irrespective of the depth of cultural wealth a civilization has produced, barely any of them have been free of power tussles.</p> <p>The group was also responsible for destruction of the Buddhas of Bamiyan<sup class="footnote-reference"><a href="#buddha-bamiyan">1</a></sup> in 2001.</p> <p><img src="/images/buddha_bamiyan.jpg" alt="Buddha of Bamiyan" /> <em>Artistic rendition of the Buddhas of Bamiyan</em></p> <p>Buddhism is a gift of India. Interestingly, it is not popular in India. However, many countries have a sizeable Buddhist population - Bhutan, China, Japan, Vietnam, Cambodia etc.</p> <p>This demolition wasn't an isolated event. The demolition wasn't done because of the specific ways we see the Talbian group.</p> <p>Its a power tussle. It knows no boundaries of country, religion or sect. Much has been demolished throughout the human history.</p> <p>Back here in India, the Sanchi Stupa is said to have been once demolished during the rule of own king - Pushyamitra Shunga.<sup class="footnote-reference"><a href="#buddhist-claims-pushyamitra">2</a></sup></p> <p><img src="/images/sanchi-3.jpg" alt="Sanchi Stupa" /> <em>Sanchi Stupa No. 3</em></p> <h2 id="the-once-largest-mosque">The once largest mosque</h2> <p>Abbasid caliph Al-Mutawakkil commissioned the Great Mosque of Samarra<sup class="footnote-reference"><a href="#mosque-samarra">3</a></sup> in 9th century. Spreading over an area of 17 hectares, it was the largest mosque in the world at the time.</p> <p><img src="/images/samarra_mosque.jpg" alt="Great Mosque of Samarra" /> <em>The Malwiya Tower beside walls of The Great Mosque of Samarra</em></p> <p>It remained the largest mosque for the next 400 years, until the armies of Mongol ruler Hulagu Khan demolished major parts of this mosque during the invasion of Iraq in 1278.</p> <p>In April 2005, insurgents bombed the tower, causing more destruction. They did this claiming that US troops were using the minaret as a lookout position. The British, however, claim that the attack was done to incite Sunni-Shia violence.</p> <p>Power tussle, again?</p> <h2 id="demolition-is-a-hallmark-of-civilization">Demolition is a hallmark of civilization</h2> <p>The demolition of Buddha statues or the Great Mosque or any other such structure serve a greater lesson. That we let our power tussle dominate the gifts we create.</p> <p>We created groups to fight for power - nation, religion, sect, caste etc. We put stickers over structures. This belongs to us. That belongs to them.</p> <p>But what we lose in this tussle is the glory of human race. No sticker. The demolished Buddha Statue is a grave loss for not just the Buddhists, but every human on the face of this planet. Remains of The Great Mosque of Samarra are a reminder to every human that 'faith builds, but thirst for power demolishes'.</p> <p>They are not simple structures associated with their respective religions. They are the result of collective human effort and thousands of years of human progress. They are artifacts by those who shaped the course of our civilization. They are architectural feats every human should be proud of. They are symbols of human greatness - meant to be taken pride in.</p> <p>So what if they're destroyed? Who can correct history? Do we rush to correct every historical mistake or do we look forward and learn? What has happened shall not be undone. Who are we to repeal history?</p> <p>And despite this fact, the fact remains that civilizations demolish. Whether it was The Parthenon<sup class="footnote-reference"><a href="#parthenon">4</a></sup> suffering damage due to wars or the Temple of Bel<sup class="footnote-reference"><a href="#bel-temple">5</a></sup> targeted by ISIS - destruction is a defining characteristic of our civilization.</p> <p><img src="/images/parthenon.jpg" alt="Parthenon" /> <em>The Parthenon in Athens, Greece<br>It was partly destroyed in 1687 during the 15 year Great Turkish War while being used as a gunpowder store. A firing hit on the powder magazine causing an explosion. The cella collapsed, central part of walls blown out and much of Phidias’ frieze brought down. Many columns also toppled, causing the architraves, triglyphs and metopes to come tumbling down.</em></p> <p><img src="/images/bel_temple.webp" alt="The Temple of Bel Palmyra, Syria" /> <em>The Temple of Bel, Palmyra, Syria (2009)<br>It was bombed by the ISIS on 30 August 2015 causing much of the preserved remains to be destroyed. The temple was the most important one from antiquity in the Middle East.</em></p> <p><img src="/images/bel-remains.jpg" alt="Bel Temple Entrance" /> <em>Remains of the Temple of Bel after it was damaged<sup class="footnote-reference"><a href="#isis-news">6</a></sup></em></p> <p>We have the technical knowhow to restore the lost Buddha statues. We can build several similar Buddha statues around the world. But thats not important from historical perspective. Whats important is the present state of Buddha statues in Bamiyan. It serves a greater memory. It stands as a testification to the architectural feats we achieved centuries back and also a symbol of tyranny and wrongdoings of a certain group.</p> <hr> <p>There is another demolition that haunts the hallways of contemporary Indian narrative. Does demolition serve victory? Is it worth being recorded in the books forever for having demolished a 465 year old structure for religious dominance? Is it worth one avenging demolition by another demolition?</p> <p>Who ensures that 500 years down the line, someone else will not avenge our present actions the way we avenged certain acts from five centuries back?</p> <p>Or does rebuilding ever serve a victory? Can something born out of a highly political and communal issue really hold its ground for being a divine place?</p> <p>We dig out structures of past; and structures dig out our past memories. They remind us of their history. They stand as a symbol. What shall such a structure we celebrate today stand for? That the masses of a culture as rich as ours agreed to be swayed in the name of religion?</p> <h2 id="demolition-all-the-way-down">Demolition all the way down</h2> <p>Structures will be destroyed. Either by man or by nature. Cultural wealth remains. The hallmarks of a civilization must be preserved.</p> <p>Our hallmark should be peace and harmony. Not demolition.</p> <p>The ability to see beauty in structures not branded by your group has been stolen from you. The ability to see humans as humans has been demolished. The cultural harmony we once took pride in, is a matter of history books.</p> <p>Demolition, three decades back. Demolition today.</p> <p>It looks like what we long desired has been gifted to us. Its been built. Its being celebrated.</p> <p>But beneath our feet, something else - more pround - has been demolished away.</p> <p><em>22 January 2024</em></p> <hr> <small> <h4>Footnotes</h4> <div class="footnote-definition" id="buddha-bamiyan"><sup class="footnote-definition-label">1</sup> <p>The Buddhas of Bamiyan were two 6th-century monumental Buddhist statues in the Bamiyan Valley of Afghanistan. <a href="https://en.wikipedia.org/wiki/Buddhas_of_Bamiyan">Wikipedia article</a></p> </div> <div class="footnote-definition" id="buddhist-claims-pushyamitra"><sup class="footnote-definition-label">2</sup> <p><a href="https://en.wikipedia.org/wiki/Pushyamitra_Shunga#Buddhist_accounts">Buddhist claims about Pushyamitra Shunga</a></p> </div> <div class="footnote-definition" id="mosque-samarra"><sup class="footnote-definition-label">3</sup> <p><a href="https://en.wikipedia.org/wiki/Great_Mosque_of_Samarra">The Great Mosque of Samarra</a></p> </div> <div class="footnote-definition" id="parthenon"><sup class="footnote-definition-label">4</sup> <p><a href="https://en.wikipedia.org/wiki/Parthenon">The Parthenon</a></p> </div> <div class="footnote-definition" id="bel-temple"><sup class="footnote-definition-label">5</sup> <p><a href="https://en.wikipedia.org/wiki/Temple_of_Bel">Temple of Bel</a></p> </div> <div class="footnote-definition" id="isis-news"><sup class="footnote-definition-label">6</sup> <p><a href="https://edition.cnn.com/2015/08/31/middleeast/palmyra-temple-damaged/index.html">ISIS destroys Temple of Bel in Palmyra, Syria, U.N. reports</a> </small></p> </div> You've been ordered to hate this picture Snehit Sah [email protected] http://snehit.dev 2024-01-12T00:00:00+00:00 2024-01-12T00:00:00+00:00 https://snehit.dev/posts/youve-been-ordered-to-hate-this-picture/ <p>The divisions never disappeared. When we agreed its not ok to divide on basis of religion on race, we divided ourself on basis of nation.</p> <p>A quiet tomb asks if this was all a game of power - shifting from religious and racial leaders to nationalist leaders.</p> <p>What has changed?</p> <p>You still believe in hate.</p> <h2 id="you-ve-been-ordered-to-hate-this-picture">You've been ordered to hate this picture</h2> <p><img src="/images/maldives.jpg" alt="Maldives" /></p> <p><small>Photo by <a href="https://unsplash.com/@matheenfaiz?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Matheen Faiz</a> on <a href="https://unsplash.com/photos/green-trees-near-body-of-water-under-blue-sky-during-daytime-xQwa0HbMfYM?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a></small></p> Inter Caste Marriage & Statistics Snehit Sah [email protected] http://snehit.dev 2024-01-10T00:00:00+00:00 2024-01-10T00:00:00+00:00 https://snehit.dev/posts/intercaste-marriages-and-statistics/ <p>I came across a study<sup class="footnote-reference"><a href="#study">1</a></sup> by NCAER and University of Maryland that claimed only 5% of Indian marriages to be inter caste. <sup class="footnote-reference"><a href="#what-is-caste">2</a></sup></p> <p>Data points, while incredibly useful, may hide social facts or value driven choices.</p> <p>The data collection process involved asking female respondents whether their natal family belongs to same caste as their husband's family. Based on this survey, it was concluded that as per the sample, only 5% inter caste marriages. Such a questionnaire unfortunately conceals individual choices in personal matters.</p> <p>What should be the ideal percentage of people opting for inter caste marriages? 10%? 50%? 100%? <strong>We don't even know what number to target.</strong> It may be such that in a hypothetical and ideal non biased world, the percentage of inter caste couples are 30%. The other 70% chose to marry within their caste by their independent decision and not due to rigid caste based liabilities.</p> <p>But, what exactly is that magic number? We sadly don't know.</p> <p>These statistics are useful majorly for comparisons. In this case, the previous similar study a decade back also reported approximately 5% inter caste marriage rates. However, sensationalization and high stress on consolidated indicators lead the masses into a race to blindly shoot up the statistics.</p> <p>People may very well choose to marry within their caste. Not beacuse they have resentment for other castes, but because they prefer living with a person of culturally similar background. It might so happen that the person they fell in love with happened to be of a similar caste. Or it may be that when looking for a spouse, they didn't look beyond their caste for no specific negative reason.</p> <p>It will make more sense to know the incidence of <em>failed</em> inter caste marriages (or attempts for such). The threat isn't exactly from the 5% figure. Rather, the stress should be on protecting couples who want to opt for inter caste marriages. There is unreasonably high prevalence of violence against inter caste couples.<sup class="footnote-reference"><a href="#deccan-chronicle-article">3</a></sup> Awareness and open mindedness doesn't help if the result of their actions leads to brutal backlash. Enforcing strict rules against such perpetrators will make inter caste couples feel safer in their act.</p> <p>Here's my idea of a survey - asking people whether <em>in the past</em> they wanted to go for an inter caste marriage. Then note down the percentage that decided against it due to familial or societal restrictions. That should serve more value in my opinion. In such a survey, we can objectively claim that a higher statistic correlates with better outcomes. A 100% outcome will be considered ideal. It gives us a direction and goal to aim at.</p> <p>Urbanization and shift into the modern lifestyle has been a driving force for changing caste related practices. However, the perpetuation takes new forms. Brahmin Matrimony<sup class="footnote-reference"><a href="#brahmin-matrimony-website">4</a></sup> is a website which does exactly what the name says - finding a match with the Brahmin filter. As if the parent company knew what it was getting up to, they omitted Brahmin Matrimony on their homepage<sup class="footnote-reference"><a href="#matrimony-homepage">5</a></sup>, even though they mention their other matrimonial sites. These services have more such filters and make it easier to carry on the structures which we supposedly aim to leave behind.</p> <p>It is difficult moulding a person's beliefs once they're solidified. If caste based filtering in the real world gets discouraged, the practice will very well be continued via internet matrimonial sites.</p> <p>What seems to be practical and objectively directed towards a positive goal is to provide a safe environment for people who want to opt for inter caste marriages. Let the practice spread naturally and allow the incidence of inter caste marriages to organically reach the stable point.</p> <hr> <small> <h4> Footnotes </h4> <div class="footnote-definition" id="study"><sup class="footnote-definition-label">1</sup> <p><em>Just 5% of Indian marriages are inter-caste: survey</em> - <a href="https://www.ncaer.org/news/just-5-of-indian-marriages-are-inter-caste-survey#">link</a></p> </div> <div class="footnote-definition" id="what-is-caste"><sup class="footnote-definition-label">2</sup> <p>For the uninitiated, caste is a descent based hereditary and closed social stratification system common in India. There are many attributes and outcomes related to caste, but for the context of this post, it suffices to know that caste is an endogamous group i.e. a person shall typically marry someone from the same caste. This strengthens social divisions as caste divisions are also related to exploitation, status etc.</p> </div> <div class="footnote-definition" id="deccan-chronicle-article"><sup class="footnote-definition-label">3</sup> <p>A simple web search will yield many reports like this one: <a href="https://www.deccanchronicle.com/nation/crime/160823/couple-arrested-brutal-attack-dalit-woman-tirupati.html">Brutal Attack on Dalit Woman and Mother After Inter-Caste Marriage</a></p> </div> <div class="footnote-definition" id="brahmin-matrimony-website"><sup class="footnote-definition-label">4</sup> <p>Brahmin Matrimony: <a href="https://www.brahminmatrimony.com/">website link</a></p> </div> <div class="footnote-definition" id="matrimony-homepage"><sup class="footnote-definition-label">5</sup> <p>Matrimony.com: <a href="https://www.matrimony.com">website link</a></p> </div> </small> I Come To Claim Snehit Sah [email protected] http://snehit.dev 2023-11-16T00:00:00+00:00 2023-11-16T00:00:00+00:00 https://snehit.dev/posts/i-come-to-claim/ <p>No warrior comes empty handed but my hands are tied today. For I carry not my weapons, but this jar of water from my corner of the world.</p> <p>People back there used to throw coins in this water.<br> <em>(Did their wishes come true?)</em></p> <p>Some took a sip.<br> <em>(Did their throats sweeten?)</em></p> <p>This water has flown through cities and villages, through time and space, through the space between us. Twenty years, I've been still, yet spilling over on every side. So, I bring to you this jar of water - as sparkling and sweet as ever.</p> <p>I come to make true the pictures you wish to live through. To be the honey trickling down your throat on dry evenings, to be the warmth under your feet on cold nights.</p> <p>I come to be your war commander. To shield from fire, to put our victory flags all the way to the east.</p> <p>I come to be the evenings you settle down in. I come to be the cups you sip your tea from, the sugar cubes you drown and the spoon you swirl.</p> <p>I come to claim, no more than a hamlet in your heart, nothing less than a lifetime in your heart.</p> <div style="text-align: center">💜🤍</p> Paper Planes Snehit Sah [email protected] http://snehit.dev 2023-10-17T00:00:00+00:00 2023-10-17T00:00:00+00:00 https://snehit.dev/posts/paper-planes/ <p>The setting sun paints a bright crimson behind the three-storey buildings. They vividly contrast each other, for the buildings were painted in white once and now have a calm off-white colour. Trees add to the dramatic effect. They look dark. Incomprehensible structures standing in front of the vivid sky.</p> <p>There's beauty in the world begging to be noticed. Demanding attention.</p> <p>Beneath this everlasting natural beauty, I chart my way on this dark man-made asphalt. Which road leads to you? Even with the greens and reds, my eyes are fixated on the roads I tread, for these are my way to the crimson I really want to taste.</p> <p>Power cables hanging between poles and the interlocked tiles on the walkway not so quite in unison. Roads breaking apart at edges and carrying minor potholes.</p> <p>In between these two worlds, I fly my paper planes. Dreams, longing, love. My paper planes wind around the place, taking unexpected twists and turns, but land at the finish line I'm chasing. Where the two worlds meet into one, I'll be walking on this asphalt under crimson sky, with you.</p> <p>When the sun has set and the crimson faded, I'm reminded that my evenings will be shadowed by the taste I want from life. A very patient wait.</p> <p>I fly yet another paper plane. Wish this too lands at the finish line, right where you are.</p> Farming Your Insecurity To Sell You Products Snehit Sah [email protected] http://snehit.dev 2023-09-24T00:00:00+00:00 2023-09-24T00:00:00+00:00 https://snehit.dev/drafts/insecure/ <p>I recently made a short post about how our insecurities are exploited by companies to sell products to us. It was centered around the individual and the need for their self acceptance. (You can read it <a href="https://snehit.dev/posts/if-you-woke-up-beautiful/">here</a>)</p> <p>This time, I take up the same topic again with a slight twist - I write it from an external perspective, with some <em>name and shame</em> here and there. Jumping right in!</p> <h2 id="fashion-industry">Fashion Industry</h2> <p>Nobody is a stranger to clothing industry. New trends popping up faster than my semester exams ensure that people always have something or the other to buy.</p> <p>Foundation garment (or <em>shapewear</em>) presents a new tier of absurdness. Whats the basis of shapewear? <em>"Your body shape is bad and not likaeble, so instead of eating healthy / exercising, here's a super tight undergarment that will give the desired shape to your body"</em></p> <p>Victoria's Secret, a popular American lingerie, clothing and beauty retailer has a lot going against it. In <em>"Victoria's Dirty Secret: How Sociocultural Norms Influence Adolescent Girls and Women"</em> (2008), the authors have noted that dissatisfaction in women about their bodies is influenced by sociocultural norms for ideal apprearance that are pervasive in society. The company's marketing practices are long criticized for delivering the message that their models are a realistic standard of beauty. Their <em>Perfect Body Campaign</em> also drew a lot of flak for advertising unrealistic standards and perpetuating negative body images.</p> <p>Apart from advertisements, Victoria's Secret has also been repeatedly criticized for cultural appropriation.</p> <p>While lot of us see fashion from the lens of clothing and accessories, fashion doesn't always <em>need</em> to mean just clothing.</p> <p>Welcome to...</p> <h2 id="body-parts-as-fashion">Body Parts as Fashion!</h2> <p>Yes, its not just your clothes.</p> <p>I was first introduced to this idea from a <a href="https://www.youtube.com/watch?v=cpdxKp8nDfc">video by Karolina Żebrowska</a>.<sup class="footnote-reference"><a href="#karolina">1</a></sup></p> <p>That was when I noticed physical homogenity among those who kept up with the trends. Plump lips became trendy. Freckles became fashion.</p> <p>Beauty standards became much more precise because that funds the cosmetic surgery industry. Botox was what I used to read about during school. These days, a lot more procedures have become common.</p> <h4 id="the-first-brush-buccal-fat-removal">The first brush - Buccal Fat Removal</h4> <p>The first proceduce to have made me think about the drama going on was <em>buccal fat removal</em>. This surgery is for people who don't want fat in their lower cheek / jawline which making their face look round. I have a naturally round face and was never insecure about it. When I got to know that there's a surgery which removes fat near the jawline I was astonished. Not because of the existence of this surgery but upon seeing perfecty normal looking people opt for this.</p> <p>For a brief summary, what happens is that the surgeon makes small incision on the inside of mouth to expose buccal fat pads, remove the fat and then close the incision with stutures.</p> <p>I didn't see the utility of all this for an average person.</p> <h4 id="and-then-i-got-to-know-more">And then I got to know more</h4> <p>It slowly become clear that the new beauty standards being invented were the ones which can be easily solved with cosmetic surgeries.</p> <p><em>Keeping Up With The Kardashians</em> popularized many fashion trends.<sup class="footnote-reference"><a href="#kardashian-trends">2</a></sup> One of them being a popular liking for a <em>specific</em> type of hips. American Society for Aesthetic Plastic Surgery <a href="https://www.businessinsider.in/science/health/news/plastic-surgeons-say-theyre-more-booked-up-than-ever-as-demand-for-procedures-like-brazilian-butt-lifts-break-records/articleshow/84795894.cms">reported a 90% increase in Brazillian Butt Lift surgeries</a> (BBL) between 2015 - 2019. What caught attention was the fact that people were opting for this surgery despite it having a high failure rate - leading to above normal death statistics. A <a href="https://www.medpagetoday.com/special-reports/exclusives/103970">Medpage article</a> reported on the deadly procedure.</p> <p>Funnily enough, it has been reported that Kim and Khloe Kardashian have had their BBL procedures reversed. So, will people who successfully underwent the deadly BBL surgery now go for a reversal?</p> <p>Nobody seems to understand that fact that celebs have access to big pockets and highly trained doctors which makes their surgeries lot less dangerous. The common public doesn't have access to them and face complications in many such surgeries.</p> <p>The obsession with hips have never faded. There's a naturally occuring depression on outside of the upper leg, just below the hip bone - now commonly called the "hip dip". A natural part of the body now needs to conform to set standards. There are surgeries which redistribute fat (i.e. <em>liposculpting</em>) to fill in the dip with fat and get a smoother curvature.</p> <p>Earlobe reduction. Anyone? Another legitimate surgery which <em>some</em> people genuinely needed is now fashion. Tiny earlobes are desired. Get operated!</p> <p>Gen Z blessed popularized another phrase - "Negative Canthal Tilt". This was popularized by TikTok. What they basically say is that if a person has down turned eyes, its "over for them" (whatever that's supposed to mean).</p> <p>Its not even about attractiveness anymore. New terms are manufactured to negatively refer to otherwise normal aspects of the body. Whats up with "bat wings", huh? What people now negatively refer to as "saddlebags" is something I find pretty. Why should everyone be a perfectionist with every corner of their bodies conforming to the beauty standards? So that people get worried about their "bat wings" or "saddlebags" and rush for (expensive) surgeries?</p> <p>To end this (sub)section, here's an article about "leg lengthening" surgeries becoming popular among men - <a href="https://www.nbcnews.com/health/mens-health/leg-lengthening-surgery-gains-popularity-men-seeking-taller-rcna79819">Article on NBC News</a>. Somehow, men really have the need to increase their heights because society told them that taller men are desired.</p> <h3 id="classical-make-up-and-looks-game">Classical Make-up and Looks Game</h3> <p>This one's a no brainer. Women were made to hate the natural aspects of their own bodies. Hair removal industry can't stop growing. Lash extensions, catastrophic levels of makeup, extensive cosmetic skin care etc were probably never needed in the first place, but have now become commonplace.</p> <p>Those who weren't into cosmetics were engulfed by the diet industry scams. People were brainwashed by media into believing that a specific body type is perfect and that mushroomed a huge industry which came with its own scams. The US Federal Trade Commission has an <a href="https://consumer.ftc.gov/articles/truth-behind-weight-loss-ads">article about weight loss scams</a>.</p> <p>It wouldn't be far fetched to think that the only reason why men aren't too much into cosmetic makeup is because nobody has yet told them they need it. One day, a big cosmetic company will wonder why they can't tap into 50% of the population and might move on to popularizing makeup for men. If this sounds unbelievable, then know that something similar happened a century back when women didn't smoke and a company did extensive targed advertising to market cigarettes to women.</p> <h3 id="trends-must-keep-changing">Trends Must Keep Changing</h3> <p>Trends can't stay stagnant. This business thrives on constantly making consumers run after <em>new</em> trends. Fuller breasts become trends. So people run for breast implant surgeries. Few years later, the same fuller breasts are out of fashion, so people run again, to get their implants <em>removed</em>!</p> <p>Thin eyebrows were fashionable a decade back. Around 2016, thicker eyebrows became fashionable and now they're again going out of trend. Thin lips were pretty a decade back. Now its fuller lips which people find pretty. Slim bodies were the norm in late 2000s. Recent years saw curves becoming more accepted, only for slim bodies to start becoming popular once again.</p> <p>Fashion trends keep disappearing and then reappearing. TikTok has brought older trends back in public attention and I wonder if <a href="https://en.wikipedia.org/wiki/Heroin_chic">Heroin Chic</a> might actually make a mainstream comeback. With the focus on fuller bodies since past few years, the trend will very well shift back to slim bodies being hailed as perfect.</p> <h2 id="love-industry-todo-content-missing">Love (Industry!) [TODO; content missing]</h2> <p>Love and marriages have been a part of human history since the beginning. Building an industry around it isn't that old of a phenomenon though.</p> <p>love equals price of gifts</p> <ul> <li>Tinder recently launched a $500/month VIP subscription. No its not pay to win yet.</li> </ul> <p>People are dating more and breaking up more often (because its easier to find new partner). This is fuelling the online dating industry.</p> <h2 id="parenting-isn-t-cheap-todo-doesn-t-discuss-how-the-spending-is-because-parents-have-been-trapped">Parenting Isn't Cheap [TODO; doesn't discuss how the spending is because parents have been trapped]</h2> <p>I can go on a continual discussion about how economy and work distances the parent from children. Thats not the main agenda here though.</p> <p>New parents are preyed upon to extract out their money. Every parent wants the best for their child. Companies know that very well and will happily exploit parents.</p> <p>Hospital bills are over the moon. No point discussing that.</p> <p>A nanny in the USA costs an average of $20/hour. Assuming 40 hour service a week, the expenditure adds to $800/week or $3200/month. In a HCOL area, this estimate shoots much higher.</p> <p>Baby formula is not cheap and is presented as the better alternative to (much healthier) natural breast milk. Some toungue in cheek remarks often say that baby formula advertisements frighten women, leading to release of <a href="https://en.wikipedia.org/wiki/Cortisol">cortisol</a>, causing them to stop lactating.</p> <p>With growing children now being hooked to internet from a very early age, advertisements targeting them are super common.</p> <p>The sad part is that the rise in infant care expenditure is also a result of parents not giving enough time and effort to the children and instead substituting themselves with whatever money can buy.</p> <h2 id="funeral-homes">Funeral Homes</h2> <p>One doesn't usually think of this since it never crosses our minds how one can make money off the deceased.</p> <p>Predatory directors at funeral homes are known to upsell services.</p> <blockquote> <p>"Upselling is also common with funeral directors basically hinting that if you loved the departed, you should consider a more expensive coffin which might be marked up by a thousand per cent,” says Professor van der Laan. <br> <br> "Upselling also goes on in relation to flowers and a range of other things that you actually don't need."</p> </blockquote> <p>(taken from an <a href="https://www.businessinsider.com/study-upselling-by-predatory-funeral-directors-can-add-1000-to-the-cost-of-a-funeral-2017-5?IR=T">article on Business Insider</a>)</p> <p>Services are upsold taking support of emotional triggers. "These expensive flowers from a remote village in France is exactly what your loved one would have wanted." Very well.</p> <h2 id="alcohol-todo-describe-more-about-advertisements">Alcohol [TODO; describe more about advertisements]</h2> <p>(I really did have to come here too)</p> <p>While alcohol advertising is banned in India, it is legal in many other countries. There's not much good to say about alcohol, so the advertisements are nearly always solely based around fears and insecurities. <em>"Drinking this alcoholic beverage makes you fun at parties!</em></p> <p>Ever heard of having fun without alcohol?</p> <h2 id="peach-should-smell-like-peach">Peach Should Smell Like Peach!</h2> <p>Deodorant industry has made everyone think that they smell like dirt and can't step out of their bedroom without a spray. Its not just the armpits or back now though.</p> <p>Lume Deodorants homepage has video of their founder &amp; CEO Dr. Shannon Klingman in front of a lady with her legs spread apart. Dr. Klingman proceeds to advertise their deodorants, which (in their words) can be used for "lady bits", "chesticles" and "buttcracks" among other areas.</p> <p>The pubes are <em>supposed to</em> smell like pubes. Derriere will smell like derriere. It doesn't need to smell like a rose garden. Companies like Lume convey that every crevice of our body smells foul and it <em>must</em> be fixed by their revolutionary products. This self hatred towards one's own body is these days called "body positivity" (the irony!).</p> <p>If someone is really close enough to the butts to be able to smell them, the person either <em>consented</em> for that (in that case the better be ready for it) or they're crossing boundaries (in that case, better call the cops).</p> <h2 id="next-level-of-personal-hygiene">Next Level Of Personal Hygiene</h2> <p>Sanfe, a company started by two men from IIT Delhi, claims to make 'personal hygiene' products for women.</p> <p>As if the insecurity inflicted by companies surrounding skin complexion and body shape was not enough, this company proceeds to introduce products for nipple lightening, and whitening products for intimate areas.</p> <p>They failed to report any scientific backing for their products and haven't disclosed ingredients. They haven't acknowledged the fact that nipple color is naturally dark and cannot be lightened in a safe manner. Neither have they put forth convincing evidence for safety of their products for intimate areas.</p> <p>Their sole selling proposition happens to be the artificial fear and FOMO induced due to their pitching and changing public perceptions.</p> <h2 id="the-dental-world">The Dental World</h2> <p>Healthy teeth are supposed to be white. But not a perfect white for everyone. They can go in a variety of shades and all of them will be healthy.</p> <p>A lot of people are unaware of this fact and are reliant on whitening strips marketed to us. Tooth bleaching procedures are common and are offered at most dental clinics, even though most people don't need it.</p> <p>They're just insecure about not having perfectly white teeth.<sup class="footnote-reference"><a href="#teeth-discolor">3</a></sup></p> <p>What about bad breath? For a lot of people, bad breath is a result of coated tongue<sup class="footnote-reference"><a href="#coated-tongue">4</a></sup>, plaque buildup or food bit stuck between the teeth. Beyond that, <em>mouth is supposed to smell like mouth</em>, not like a mint plantation. Listerine disagreed.</p> <p>Listerine, which we commonly recognize as a mouthwash, was invented in 19<sup>th</sup> century as a powerful surgical antiseptic. To sell it to a broader base, the company marketed diluted versions of their formula as a floor cleaner and even as a cure or gonorrhea.</p> <p>In 1920s, Listerine piggy backed on a then-obscure medical term for bad breath - "chronic halitosis", for which Listerine presented itself as a solution. There they started their aggressive advertising campaigns. Quoting from <a href="https://freakonomics.com/"><em>Freakonomics</em></a> by Steven D. Levitt and Stephen J. Dubner:</p> <blockquote> <p>Listerine's new ads featured forlorn young women and men, eager for marriage but turned off by their mate's rotten breath. "Can I be happy with him in spite of that?" one maiden asked herself. Until that time, bad breath was not conventionally considered such a catastrophe. But Listerine changed that. <br><br> As the advertising scholar James B. Twitchell writes, "Listerine did not make mouthwash as much as it made halitosis." In just seven years, the company's revenues rose from $115,000 to more than $8 million.</p> </blockquote> <p>The alcohol in Listerine can kill good bacteria and makes mouth dry, further <em>promoting</em> bacterial growth, thus making you reliant on the product.</p> <hr> <small> <div class="footnote-definition" id="karolina"><sup class="footnote-definition-label">1</sup> <p>I'm not a regular watcher of <a href="https://www.youtube.com/@KarolinaZebrowskax">Karolina Żebrowska</a>. Though, her rants about fashion can get interesting.</p> </div> <div class="footnote-definition" id="kardashian-trends"><sup class="footnote-definition-label">2</sup> <p>The Kardashians have to their name the credit for starting a lot of unneeded trends and promoting a lot of products and procedures. They are known to run a big alternate fashion business and <a href="https://www.theguardian.com/fashion/2019/jan/28/they-can-sell-anything-how-the-kardashians-changed-fashion">they can sell anything</a>.</p> </div> <div class="footnote-definition" id="teeth-discolor"><sup class="footnote-definition-label">3</sup> <p>In case you believe your teeth are being discolored due to a medical issue, visit a dentist.</p> </div> <div class="footnote-definition" id="coated-tongue"><sup class="footnote-definition-label">4</sup> <p>Thicker white patches on tongue can be a sign of infection.</p> </div> </small> Shopping Even When You Aren't Snehit Sah [email protected] http://snehit.dev 2023-09-23T00:00:00+00:00 2023-09-23T00:00:00+00:00 https://snehit.dev/posts/shopping-even-when-you-arent/ <p>My Google Drive has an old spreadsheet. A list of books from Amazon that I wished to buy once I had enough money. It was made during August 2020 as far as I can remember.</p> <hr> <p>I used to occasionally spend time on shopping apps. I didn't have enough time to scroll through shopping apps daily, but when I did, I used to be consumed into it, adding items on my 'wishlist'. I didn't even know that word before Amazon app came along. It was an easy way to mark items you want to have but can't purchase right away.</p> <p>When do we get that money we hope for? For me, it was half a decade. I was yet to enter university. Saving items that I'll purchase half a decade later didn't seem extraordinary to me.</p> <p>Just three years since that month and I've already had a one eighty degrees personality change. My wishlists are useless now and serve no purpose other than reminding me that wasting time on consumer traps is of no real use.</p> <p>Character development maybe.</p> <hr> <p>Should I wonder how much time I spent mindlessly scrolling on shopping apps? I wasn't even a serial buyer - I barely used 3 apps, which I've come to know is a small number for the folks these days.</p> <p>Back when we didn't have the privilege of smartphones, purchases used to happen only when we want to. And we used to usually purchase what we decided to. Although advertisment did do its magic to make us buy more things, but as a whole, shopping spree was triggered by us, not them.</p> <hr> <p>How much time are we spending just looking at products online? Products have jumped out of dedicated shopping apps and slid into our peripheral vision due to advertising. Social media feeds are littered with advertisements catered to your interest profile. People are being made to waste a lot of mental energy just to make them aware of the many more ways they can fall into the trap of consumerism.</p> <p>Back then it was a matter of effort to go to the store. It wasn't so convenient to randomly pop into the store just to look (and not buy) and do that regularly. But with phones in our hands and products brandished to us by advertisement, browsing products has become a pastime.</p> <p>Scrolling through and endless list of products, making wishlists, checking out offers etc. now form regular habits.</p> <p>The online shopping boom also had another side effect - people now know about lot more products. Not that they necessarily need those products, but now they know about its existence and a percentage of them obviously have that internal itch to purchase it. This is not a new tactic by companies. Creating artificial needs is a long known technique. Online shopping just makes it easier for companies to ignite the artificial feeling of wanting an item about whose existence the consumer didn't even know about until a day before.</p> <hr> <p>Its funny how we have been taught to behave like consumers even when we don't exactly want to purchase anything. The mental conditioning happens since childhood and its very strong by the time we have purchasing power.</p> <p>As a rule, I no longer keep any shopping app installed on my phone. If I need to purchase something online, I install the app, make my purchase and uninstall that app the very day my item arrives. No wishlists, no senseless browsing for products I don't need.</p> <p>I won't say that my expenses have dropped - they weren't high anyways. But for sure every purchase I make now seems to be because of a need arising out of my own self rather than being externally induced.</p> <p>Guess thats a win.</p> Its Not Dependency Snehit Sah [email protected] http://snehit.dev 2023-09-16T00:00:00+00:00 2023-09-16T00:00:00+00:00 https://snehit.dev/posts/its-not-dependency/ <p>I read a short poem by <a href="https://en.wikipedia.org/wiki/Jean_Little">Jean Little</a>, titled "Oranges".</p> <blockquote> <p>I peel oranges neatly.<br> The sections come apart cleanly, perfectly in my hands.<br> <br> When Emily peels an orange, she tears holes in it.<br> Juice squirts in all directions.<br> <br> “Kate,” she says, “I don’t know how you do it!”<br> <br> Emily is my best friend.<br> I hope she never learns how to peel oranges.</p> </blockquote> <p>On the first read, its playful friendship. On the fifth, one may call it a dependency inducing toxic bond.</p> <p>On the other end of spectrum, I ponder over something else. Is it not toxic to expect my partner to be an embodiment of perfection? What am I if not the one to fill her gaps?</p> <p>Life isn't about rushing to perfection every second. Perfect persons make good business partners, but not necessarily the best life partners. Its the tiny quirks someone else notices and falls in love with. Anyone can provide the standard parameters - money, body etc. But its my quirks that make me unique.</p> <p>Life is about revelling in the tiny details that we won't find in anyone else.</p> <p>While the theory of <em>provider</em> and <em>receiver</em> in relationships is indeed flawed, one shouldn't extend this frame of reference to every little facet. Many times, good people don't want to correct their partner 24x7.</p> <p>Rather, they want to instill a sense of inner satisfaction in their partner, that they'll be accepted and loved in spite of their natural flaws. Don't we all have our own tiny quirks? Nobody is perfect and self sufficient. Not just relationships, but even large societies have remained woven together in harmony on the basis of the natural act of completing each other.</p> <p>Its not called <em>'dependency'</em>. Its called <em>'completing each other'</em>.</p> Music and Memories Snehit Sah [email protected] http://snehit.dev 2023-09-08T00:00:00+00:00 2023-09-08T00:00:00+00:00 https://snehit.dev/posts/music-and-memories/ <p>I was introduced to electronic music when I was trying to find royalty-free music for YouTube videos and stumbled across <a href="https://www.youtube.com/user/nocopyrightsounds">NCS</a> YouTube channel.</p> <p>As the years went by, I listened to quite a few genres and could figure out what kind of music I liked for different activities. I didn't have enough leisure time when I would <em>only</em> listen to music. During school too, I used to spend a decent amount of time on programming and caught the habit of listening to music while programming.</p> <hr> <p>In my class 11th mid-term exams, I got abysmally low scores and barely even passed in mathematics. I was of course mentally broken and as an escape tried listening to music. I still remember that evening when I was lying on my bed, diagonally across, with <a href="https://www.youtube.com/watch?v=BVMdrgzFR-A">Trust In Me</a> playing. I was alone as my family was out for a festival we celebrate and I had decided to stay at home.</p> <p>Contrary to what I thought, music did nothing to calm me down. Rather, the song only reminded me of the times I listened to it in the past which also meant it reminded me of all the carelessness I exhibited to get those low marks. By the time end-term examinations came, I distanced myself from the songs I listened to up till mid-terms, because those songs would remind me of my low scores and make me afraid of scoring badly again.</p> <p>Thus, a few of my playlists were said goodbye to. Five years later, I still don't dare to listen to those songs again. Songs I once liked and will certainly like listening to again. I won't listen since I'm afraid I'll again get the fear of scoring bad; something I absolutely can't afford to for the next few months/years. I'm not taking any chances.</p> <hr> <p>My school ended the very month the COVID-19 lockdown was imposed. We stayed in our homes for nearly ten months. During that time, among other things, I started listening to genres I hadn't touched before.</p> <p>Moving on from one phase of life to the next, I also changed my playlist and hopefully left memories of the past behind.</p> <p>Since I was <em>sort of</em> active with finding songs that were new to me, I'd keep adding new songs to my playlists and older ones would fade into memory. A song more or less lasted a season in my ears.</p> <p>As a result, I came to associate songs with the seasons of the year. Certain songs remind me of September of 2020. (notable mention - <a href="https://www.youtube.com/watch?v=NRLppKdK3Dk">Plastic Love by Mariya Takeuchi</a>) Some songs reminded me of the spring of 2021 (<a href="https://www.youtube.com/watch?v=wOSoswa9yfM">Nescience by Galdive</a>)</p> <p>I had just entered university. Being a person who doesn't prefer socializing, I had lots of time on my hands to be with myself. That meant I'd be listening to some or the other song while sitting alone in the corner of the classroom or when eating alone in the cafeteria. Many songs really captured my attention and used to keep playing in my head for hours every day.</p> <p>Yet, today I can't listen to them with the same enthusiasm. It's not that I've grown bored of the songs I used to listen to in 2021. I still like those songs and would still want to spend a happy evening listening to them, if only I could.</p> <p>Rewinding through them reminds me of a stage in my personal life that I prefer not to be reminded of. Music does that sadly.</p> <p>Loneliness isn't a great feeling.</p> <hr> <p>Today I felt like listening <a href="https://www.youtube.com/watch?v=QoCZYWEOPks">Aseul's 2 Weeks</a>. An underrecognized song that I had put on repeat a lot back when I discovered it in October 2022.</p> <p>As much as I wanted to listen to it, I knew that it would trigger memories I didn't want to live through again.</p> <p><a href="https://www.youtube.com/watch?v=HCTeVG-mMVU">Wish by Neko</a> is another song that I avoided today.</p> <p>In August 2022, I discovered Feng Suave, and their song <a href="https://www.youtube.com/watch?v=kc6Y1Bjxfk8">Sink Into The Floor</a>. I do not know if the song is actually sad. I really don't know.</p> <p>What I know is that I listened to this song at a time when I was in a really bad state of mind. I remember having this play on loop and falling asleep on the desk. I liked the song and regardless of what emotions it triggers in other people, all it triggers in me <em>now</em> are my worst fears.</p> <p>Out of my playlist.</p> <hr> <p>I learned the hard way that music triggers memories that you thought you'd have forgotten. A lot of songs I used to like are now links to events I don't wish to recall in favor of my mental health.</p> <p>Back as a child, when I learned about the word "nostalgia", I read that it can be triggered through not just contextual reminders, but also through senses, like smell, audio, taste, etc. Nobody told me it's not always that we want memories to be triggered.</p> <p>I write this in a perfectly okay state of mind. Satisfied that I know what is good for me and what isn't.</p> <p>It's not that I'm running out of songs to listen to. That's the least of my concerns. There are nearly infinite songs to listen to. But I've seen a change - I'm no longer the kind of person who wants to find new songs to put on repeat.</p> <p>It's not the song that matters. It's the memories and feelings we attach to them. And I've learnt that neither are many memories good or bad. It's how we take them forward and what we make out of it.</p> <hr> <p>The last time I listened to some new songs was in the first quarter of this year. I'm doing my real best to ensure that I'll forever cherish the memories those songs evoke. All the happy little events that surface to my mind when the respective song plays shall stay important.</p> <p>There's not much to listen to these days, except that one voice.</p> Teamwork Snehit Sah [email protected] http://snehit.dev 2023-09-05T00:00:00+00:00 2023-09-05T00:00:00+00:00 https://snehit.dev/posts/teamwork/ <p>I'm haven't been much of a teamwork person and have often speedran projects solo at my own pace. Working with others usually slowed me down.</p> <p>Lately I've come to realize that having the right teammate does indeed speed up the process. Its smooth and fun when the effort I need to put is reduced and in return I not only get the project done quicker, but also have a good time with the person I'm working with.</p> Decline of Home Cooking Snehit Sah [email protected] http://snehit.dev 2023-08-25T00:00:00+00:00 2023-08-25T00:00:00+00:00 https://snehit.dev/posts/decline-of-home-cooking/ <p>Food has been among our earliest needs. Whether we learned hunting or discovered fire, it indirectly helped us get better food and progress our civilization.</p> <p>Even in the modern era, food forms one of our basic needs. The classical Hindi phrase "Roti Kapda Aur Makaan", i.e. "Food, Cloth and House", aptly highlights the basic necessities of life.</p> <p>Yet, we've ended up at a point where we're looking at a future where cooking might become a lost art.</p> <h2 id="american-situation">American Situation</h2> <p>(Because the East often follows trends that the West already exhibited earlier, the discussion starts from America)</p> <p>I won't quote any specific statistic since nearly all point towards a sharp decline in consumption of home-cooked food during the 1960s-90s. Some statistics after the 90s show home-cooked food on decline while others mark it as more or less stagnant.</p> <p>The reason for this difference in statistics post-90s can be attributed to how different studies consider different items to be home-cooked or not. (If you buy frozen fries, and fry them at home, is it home-cooked?)</p> <p>Regardless, it's clear that there has been a considerable decline in the consumption of home-cooked food in the West. Proper restaurants are expensive, but with the rise of fast food chains, prevalence of frozen food, packaged meals, takeaway meals at supermarkets, etc., even those with lesser purchasing power can skip cooking at home. A recent study [1] has hinted at how Americans regardless of their socioeconomic status are cooking less than they had in the past.</p> <p>It is no surprise that the American population is also struggling with obesity and health disorders (especially heart-related).</p> <h2 id="indian-situation">Indian Situation</h2> <p>With growing incomes among the educated class, they don't hesitate to pay for food prepared by someone else. Eating out is no longer reserved for special occasions. Cooking at home is seen as a waste of time because we've been brainwashed into thinking that any activity is futile if it doesn't have economic returns.</p> <p>Food delivery services like Swiggy and Zomato have experienced very high growth in recent years. This has made it incredibly easy to have a meal from outside your home. An increasing number of families are relying on such apps regularly for their daily meals.</p> <p>We are looking at the same American situation being mirrored here - higher eating-related health issues and cultural erosion.</p> <h2 id="cooking-as-culture-and-oral-traditions">Cooking as Culture and Oral Traditions</h2> <p>I have often seen my mum ask her mum about recipes they used to have in older days. These recipes aren't recorded anywhere. They are oral traditions, passed on from one generation to the next. Going to the kitchen and cooking is the only way to preserve this culture and generational wealth.</p> <p>As a simple example, I never knew cauliflower leaves were edible and they taste good if cooked the right way. This happened only after we grew cauliflowers in our garden and my mum one fine morning served us cooked cauliflower leaves.</p> <p>But, even if I want to eat cauliflower leaves, it is possible for an average city dweller to buy them? Nope. They don't sell it in the market. I was lucky to have enjoyed them because I could grow them. But who does agriculture these days, duh? (/s)</p> <p>This is a major problem for urban families having rural or tribal roots. Rural and tribal cultures had knowledge of a much wider variety of edible fruits, vegetables, leaves, and tubers [2]. A lot of such edibles and recipes are unknown to us even now and on the verge of extinction. Most of those edibles aren't sold in the market. So people having settled in a city eventually lose touch with their traditional foods.</p> <p>Festivals or occasions (like weddings) in my culture call for specific dishes to be cooked. It's a tradition, which in turn is our identity. Preserving them is a statement against the monoculture spread by capitalists. Commercialization of food won't preserve the cultural capital our societies had.</p> <h2 id="breaking-the-classical-stereotype-causing-decline-in-home-cooked-meals">Breaking the Classical Stereotype Causing Decline in Home Cooked Meals?</h2> <p>In India, cooking has classically been a skill sought after in women. With women being in charge of the more important role of managing the house, they were expected to know - among other things - cooking too.</p> <p>With the growth of liberal thinking and the idea that women should have the right to choose what they want to do (they actually should), more and more women are spending less time at the stove. On the surface, it <em>looks like</em> job responsibilities are the number one reason why cooking at home is becoming a thing of the past. However, simply blaming a working woman doesn't lead us to the cause.</p> <p>It's the shift in perception about the responsibilities at home. The important aspects of life (i.e. family, home etc) have been reduced to the tag of "unpaid chores" now. Undervaluation of a woman's contribution to the house has made them seek value and validation elsewhere. This thinking has led even non-working women to reduce time spent cooking at home and instead delegate the work to a paid cook or just simply order food. Concepts like no-work-Sundays are also gaining traction where a stay-at-home-woman doesn't do any of the housework on weekends, in pursuit of enjoying holidays the way their male counterparts do.</p> <p>All this lies in the fact that society now sees cooking as a chore rather than an integral part of human culture. And its a common trend now - a lot of such activities that didn't have economic output, but instead fulfilled a more important purpose of keeping families happy together are being washed out into oblivion.</p> <h2 id="male-perception-is-also-hurting-the-outcome">Male Perception is Also Hurting the Outcome</h2> <p>The male perception about cooking also has its own flaws. While a lot of men from the educated class have thankfully acknowledged the fact that women don't "belong" to the kitchen, they've grossly failed to acknowledge that men too can enter the kitchen.</p> <p>This in turn fuels the desire in some women to also totally give up on cooking. They'll happily accept being ordered around by their bosses at their office, but won't take up responsibilities at home.</p> <p>Men, or families as a whole, need to understand that one doesn't have to "belong" to the kitchen to cook food. People work at an office 10 hours a day, but they don't "belong" there.</p> <p>I believe that liberal and free thinking should've resulted in more men joining hands with women to make meals and bringing a positive shift from the older setting where the kitchen used to be a place for women only. Sadly, the opposite has happened. An important part of the house - the kitchen - is becoming a neglected corner where neither men nor women are choosing to step in. "Progress" is making us give up responsibilities rather than letting us share them.</p> <h2 id="just-why-should-you-cook">Just Why Should You Cook</h2> <p>Cooking as an activity goes far beyond just providing bits to fuel our body. It is a way to ensure our overall well being and form better relationships. We should stop seeing cooking as an "unpaid domestic chore" and instead enjoy the process.</p> <h3 id="emotional-and-social-effects-of-cooking">Emotional and Social Effects of Cooking</h3> <p>These benefits are backed by research and aren't mere opinions.</p> <p>A 2021 research paper [3] highlights how cooking can contribute to overall well-being by intersecting it with the PERMA model - positive emotion, engagement, relationships, meaning, and achievement.</p> <p>A 2017 research paper [4] acknowledges how there is limited research on the connection between cooking and psychosocial aspects, but the trend of positive correlation suggests that cooking should have positive psychosocial outcomes. It highlights that different research papers have taken up the matter of well-being from different perspectives. Some papers bring out the positive relationship between cooking and improvement in self-esteem and/or confidence. Others relate cooking to a better mood and quality of life.</p> <p>A recent paper published in March 2023 [5] takes us to Japan where a big chunk of the population is in older stages of life. The research focused on men and women aged 65 or above and tried to bring out the relation between cooking skills and social relationships. This research also concluded in favour of cooking, highlighting how cooking skills led to better social relationships, which is increasingly important for the elderly to prevent social isolation and age-induced mental health issues.</p> <p>Anyone who cooks regularly - as an enjoyable daily activity and not as a chore - knows that cooking has an important role to play in mental well-being and satisfaction.</p> <h3 id="to-carry-on-your-culture-and-family">To carry on your culture and family</h3> <p>As I highlighted above, cooking has for long carried forth our culutre and oral traditions. Clothing, food and rituals are important pillars of a culture. There's an endless ocean of recipes that await you once you depart on your journey to explore what foods your culture has got to offer.</p> <p>Cooking also has a positive role to play in keeping families happier (<em>if</em> both partners take up the activity). On a lazy evening, heading to the kitchen with your partner and trying to cook a new dish could be a better bonding exercise than binging a Netflix show silently.</p> <h3 id="cooking-as-an-expression-of-love">Cooking as an Expression of Love</h3> <p>Cooking is a never-ending method to express love to someone. When I'm eating home-cooked food, its value goes far beyond just the taste. I realize how someone to whom I attach importance, put time and effort into cooking something for me.</p> <p>Days are busy and time is limited. In this wound-up world, taking out time to cook something for the beloved is a method I often resort to.</p> <p>I don't equate it to a love language. Humans have relied on food since inception and there has to be an inbuilt positive emotion attached to food someone cooked for you with love.</p> <p>Next time you think of a Starbucks or Theos date, instead ask her what dish she likes and make it yourself.</p> <hr /> <small> <p>[1] : Trends in US home food preparation and consumption: analysis of national nutrition surveys and time use studies from 1965–1966 to 2007–2008 : <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3639863/">https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3639863/</a></p> <br> <p>[2] : Tribal women’s collective in Wayanad on a mission to conserve tubers : <a href="https://www.thehindu.com/news/national/kerala/tribal-womens-collective-in-wayanad-on-a-mission-to-conserve-tubers/article67184775.ece">https://www.thehindu.com/news/national/kerala/tribal-womens-collective-in-wayanad-on-a-mission-to-conserve-tubers/article67184775.ece</a></p> <br> <p>[3] : Well-Being and Cooking Behavior: Using the Positive Emotion, Engagement, Relationships, Meaning, and Accomplishment (PERMA) Model as a Theoretical Framework : <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8071848/">https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8071848/</a></p> <br> <p>[4] : Psychosocial Benefits of Cooking Interventions: A Systematic Review : <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5862744/">https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5862744/</a></p> <br> <p>[5] : Associations of Cooking Skill with Social Relationships and Social Capital among Older Men and Women in Japan: Results from the JAGES : <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC10002414/">https://www.ncbi.nlm.nih.gov/pmc/articles/PMC10002414/</a></p> </small> Rust 23 June 2023 Snehit Sah [email protected] http://snehit.dev 2023-06-22T00:00:00+00:00 2023-06-22T00:00:00+00:00 https://snehit.dev/rust-23-06-2023/ <h2 id="inspirations-that-nobody-cares-about">Inspirations (that nobody cares about)</h2> <ul> <li>SML, OCaml: algebraic data types, pattern matching, type inference, semicolon statement separation</li> <li>C++: references, RAII, smart pointers, move semantics, monomorphization, memory model</li> <li>ML Kit, Cyclone: region based memory management</li> <li>Haskell (GHC): typeclasses, type families</li> <li>Newsqueak, Alef, Limbo: channels, concurrency</li> <li>Erlang: message passing, thread failure, linked thread failure, lightweight concurrency</li> <li>Swift: optional bindings</li> <li>Scheme: hygienic macros</li> <li>C#: attributes</li> <li>Ruby: closure syntax, block syntax</li> <li>NIL, Hermes: typestate</li> <li>Unicode Annex #31: identifier and pattern syntax</li> </ul> <h2 id="raii-example">RAII example</h2> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span>std::mutex m; </span><span> </span><span style="color:#b48ead;">void </span><span style="color:#8fa1b3;">bad</span><span>() </span><span>{ </span><span> m.</span><span style="color:#bf616a;">lock</span><span>(); </span><span style="color:#65737e;">// acquire the mutex </span><span> </span><span style="color:#bf616a;">f</span><span>(); </span><span style="color:#65737e;">// if f() throws an exception, the mutex is never released </span><span> </span><span style="color:#b48ead;">if</span><span>(!</span><span style="color:#bf616a;">everything_ok</span><span>()) </span><span style="color:#b48ead;">return</span><span>; </span><span style="color:#65737e;">// early return, the mutex is never released </span><span> m.</span><span style="color:#bf616a;">unlock</span><span>(); </span><span style="color:#65737e;">// if bad() reaches this statement, the mutex is released </span><span>} </span><span> </span><span style="color:#b48ead;">void </span><span style="color:#8fa1b3;">good</span><span>() </span><span>{ </span><span> std::lock_guard&lt;std::mutex&gt; </span><span style="color:#bf616a;">lk</span><span>(m); </span><span style="color:#65737e;">// RAII class: mutex acquisition is initialization </span><span> </span><span style="color:#bf616a;">f</span><span>(); </span><span style="color:#65737e;">// if f() throws an exception, the mutex is released </span><span> </span><span style="color:#b48ead;">if</span><span>(!</span><span style="color:#bf616a;">everything_ok</span><span>()) </span><span style="color:#b48ead;">return</span><span>; </span><span style="color:#65737e;">// early return, the mutex is released </span><span>} </span></code></pre> <h2 id="immutability">Immutability</h2> <p>from <a href="https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html">doc</a></p> <p>Vars immutable by default. Compiler warning if variable not mutated after declaring <code>mut</code>. Error if immutable variable reassigned.</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> x = </span><span style="color:#d08770;">5</span><span>; </span><span> println!(&quot;</span><span style="color:#a3be8c;">The value of x is: </span><span style="color:#d08770;">{x}</span><span>&quot;); </span><span> x = </span><span style="color:#d08770;">6</span><span>; </span><span style="color:#65737e;">// error </span><span> println!(&quot;</span><span style="color:#a3be8c;">The value of x is: </span><span style="color:#d08770;">{x}</span><span>&quot;); </span><span>} </span></code></pre> <p>Working code:</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let mut</span><span> x = </span><span style="color:#d08770;">5</span><span>; </span><span style="color:#65737e;">// &lt;-- added mut </span><span> println!(&quot;</span><span style="color:#a3be8c;">The value of x is: </span><span style="color:#d08770;">{x}</span><span>&quot;); </span><span> x = </span><span style="color:#d08770;">6</span><span>; </span><span> println!(&quot;</span><span style="color:#a3be8c;">The value of x is: </span><span style="color:#d08770;">{x}</span><span>&quot;); </span><span>} </span></code></pre> <h2 id="shadowing">Shadowing</h2> <p>refer <a href="https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing">doc</a></p> <h2 id="ownership">Ownership</h2> <p>Passing ownership from one function to another</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">let</span><span> s1 = String::from(&quot;</span><span style="color:#a3be8c;">hello</span><span>&quot;); </span><span style="color:#b48ead;">let</span><span> s2 = s1; </span><span style="color:#65737e;">// s1 moved; can&#39;t be used again :( </span><span style="color:#b48ead;">let</span><span> s3 = s2.</span><span style="color:#96b5b4;">clone</span><span>(); </span><span style="color:#65737e;">// s2 copied; both can be used independently </span></code></pre> <ul> <li>Move</li> <li>Copy</li> </ul> <p>(Move and copy are one of the many traits)</p> <h2 id="passing-ownership">Passing ownership</h2> <p>String type can take arbitrary time to Copy. Hence default action is to pass its ownership (i.e. <code>Move</code> it). On the other hand, integers are easy to copy and take deterministic time. Hence they are cloned by default (i.e. <code>Copy</code>)</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> s = String::from(&quot;</span><span style="color:#a3be8c;">hello</span><span>&quot;); </span><span style="color:#65737e;">// s comes into scope </span><span> </span><span> </span><span style="color:#96b5b4;">takes_ownership</span><span>(s); </span><span style="color:#65737e;">// s&#39;s value moves into the function... </span><span> </span><span style="color:#65737e;">// ... and so is no longer valid here </span><span> </span><span> </span><span style="color:#b48ead;">let</span><span> x = </span><span style="color:#d08770;">5</span><span>; </span><span style="color:#65737e;">// x comes into scope </span><span> </span><span> </span><span style="color:#96b5b4;">makes_copy</span><span>(x); </span><span style="color:#65737e;">// x would move into the function, </span><span> </span><span style="color:#65737e;">// but i32 is Copy, so it&#39;s okay to still </span><span> </span><span style="color:#65737e;">// use x afterward </span><span> </span><span>} </span><span style="color:#65737e;">// Here, x goes out of scope, then s. But because s&#39;s value was moved, nothing </span><span> </span><span style="color:#65737e;">// special happens. </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">takes_ownership</span><span>(</span><span style="color:#bf616a;">some_string</span><span>: String) { </span><span style="color:#65737e;">// some_string comes into scope </span><span> println!(&quot;</span><span style="color:#d08770;">{}</span><span>&quot;, some_string); </span><span>} </span><span style="color:#65737e;">// Here, some_string goes out of scope and `drop` is called. The backing </span><span> </span><span style="color:#65737e;">// memory is freed. </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">makes_copy</span><span>(</span><span style="color:#bf616a;">some_integer</span><span>: </span><span style="color:#b48ead;">i32</span><span>) { </span><span style="color:#65737e;">// some_integer comes into scope </span><span> println!(&quot;</span><span style="color:#d08770;">{}</span><span>&quot;, some_integer); </span><span>} </span><span style="color:#65737e;">// Here, some_integer goes out of scope. Nothing special happens. </span></code></pre> <h2 id="function-can-return-ownership">Function can return ownership</h2> <p>If function returns a value, the calling function can capture return data and gets ownership.</p> <h2 id="references">References</h2> <p>refer <a href="https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html">doc</a></p> <p>Use <code>&amp;</code> to pass a reference</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> s1 = String::from(&quot;</span><span style="color:#a3be8c;">hello</span><span>&quot;); </span><span> </span><span> </span><span style="color:#b48ead;">let</span><span> len = </span><span style="color:#96b5b4;">calculate_length</span><span>(&amp;s1); </span><span> </span><span> println!(&quot;</span><span style="color:#a3be8c;">The length of &#39;</span><span style="color:#d08770;">{}</span><span style="color:#a3be8c;">&#39; is </span><span style="color:#d08770;">{}</span><span style="color:#a3be8c;">.</span><span>&quot;, s1, len); </span><span>} </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">calculate_length</span><span>(</span><span style="color:#bf616a;">s</span><span>: &amp;String) -&gt; </span><span style="color:#b48ead;">usize </span><span>{ </span><span> s.</span><span style="color:#96b5b4;">len</span><span>() </span><span>} </span></code></pre> <p>But using <code>&amp;</code> doesn't mean you can edit the variable</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> s = String::from(&quot;</span><span style="color:#a3be8c;">hello</span><span>&quot;); </span><span> </span><span> </span><span style="color:#96b5b4;">change</span><span>(&amp;s); </span><span>} </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">change</span><span>(</span><span style="color:#bf616a;">some_string</span><span>: &amp;String) { </span><span> some_string.</span><span style="color:#96b5b4;">push_str</span><span>(&quot;</span><span style="color:#a3be8c;">, world</span><span>&quot;); </span><span style="color:#65737e;">// &lt;-- Error </span><span>} </span></code></pre> <h2 id="mutable-references-to-other-functions">Mutable References to other functions</h2> <p>refer <a href="https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-references">doc</a></p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let mut</span><span> s = String::from(&quot;</span><span style="color:#a3be8c;">hello</span><span>&quot;); </span><span> </span><span> </span><span style="color:#96b5b4;">change</span><span>(&amp;</span><span style="color:#b48ead;">mut</span><span> s); </span><span>} </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">change</span><span>(</span><span style="color:#bf616a;">some_string</span><span>: &amp;</span><span style="color:#b48ead;">mut</span><span> String) { </span><span> some_string.</span><span style="color:#96b5b4;">push_str</span><span>(&quot;</span><span style="color:#a3be8c;">, world</span><span>&quot;); </span><span>} </span></code></pre> <h2 id="mutable-references-within-scope">Mutable References within scope</h2> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span> </span><span style="color:#b48ead;">let mut</span><span> s = String::from(&quot;</span><span style="color:#a3be8c;">hello</span><span>&quot;); </span><span> </span><span> </span><span style="color:#b48ead;">let</span><span> r1 = &amp;s; </span><span style="color:#65737e;">// no problem </span><span> </span><span style="color:#b48ead;">let</span><span> r2 = &amp;s; </span><span style="color:#65737e;">// no problem </span><span> </span><span style="color:#b48ead;">let</span><span> r3 = &amp;</span><span style="color:#b48ead;">mut</span><span> s; </span><span style="color:#65737e;">// BIG PROBLEM </span><span> </span><span> println!(&quot;</span><span style="color:#d08770;">{}</span><span style="color:#a3be8c;">, </span><span style="color:#d08770;">{}</span><span style="color:#a3be8c;">, and </span><span style="color:#d08770;">{}</span><span>&quot;, r1, r2, r3); </span><span> </span></code></pre> <h2 id="dangling-references">Dangling references</h2> <p>Situation where a pointer is pointing to data which has been dropped</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> reference_to_nothing = </span><span style="color:#96b5b4;">dangle</span><span>(); </span><span>} </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">dangle</span><span>() -&gt; &amp;String { </span><span> </span><span style="color:#b48ead;">let</span><span> s = String::from(&quot;</span><span style="color:#a3be8c;">hello</span><span>&quot;); </span><span> </span><span> &amp;s </span><span>} </span><span style="color:#65737e;">// After function exits, the string data is dropped; </span><span> </span><span style="color:#65737e;">// and ownership of reference s is given back to main </span></code></pre> <p>This code won't compile.</p> <h2 id="error-handling-philosophy">Error handling philosophy</h2> <p>There is only ONE error which halts your program / crashes it. That is <code>panic!()</code>. No other error shall arbitrarily halt your program. If a program panics, then run the program with env var <code>RUST_BACKTRACE=1</code> to print backtrack from where error occured.</p> <p><code>panic!()</code> is called only when the error is NOT recoverable.</p> <ul> <li>trying to open a non existent file without telling Rust what to do if file doesn't exist</li> <li>trying to send network packet when there is no network connection and not telling Rust what to do when no network</li> </ul> <p>Most of the panics occur because an external requirement is not satisfied. (like existence of data on filesystem, network connectivity etc).</p> <p><strong>But the program will still NOT panic arbitrarily.</strong> If you access a file that doesn't exist, Rust won't crash the program. In the code itself YOU, the programmer, has to explicitly define what should happen if file doesn't exist. Handle the error or crash program.</p> <p>This approach to error handling makes the code verbose. There is no <em>default behaviour</em>. There is only <em>explicit behaviour</em> which YOU have defined. This verbosity comes at a benefit that if your program is crashing, then its because you ASKED it to crash. Program doesn't crash because "something went wrong".</p> <h2 id="result-type">Result type</h2> <p>Refer <a href="https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html">Recoverable Errors with Result</a></p> <p><code>Result</code></p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">enum </span><span>Result&lt;T, E&gt; { </span><span> Ok(T), </span><span> Err(E), </span><span>} </span></code></pre> <p>Functions don't return the value you expect. It returns a <code>Result</code>.</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">use </span><span>std::fs::File; </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> file_handler_result = File::open(&quot;</span><span style="color:#a3be8c;">hello.txt</span><span>&quot;); </span><span> </span><span style="color:#65737e;">// file_handler_result is of type Result&lt;std::fs::File, std::io::Error&gt; </span><span>} </span></code></pre> <p>Now YOU decide what to do with this result.</p> <p>Handling it by panicking</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">use </span><span>std::fs::File; </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> file_handler_result = File::open(&quot;</span><span style="color:#a3be8c;">hello.txt</span><span>&quot;); </span><span> </span><span> </span><span style="color:#b48ead;">let</span><span> file_handler = </span><span style="color:#b48ead;">match</span><span> file_handler_result { </span><span> Ok(file) =&gt; file, </span><span> Err(error) =&gt; panic!(&quot;</span><span style="color:#a3be8c;">Problem opening the file: {:?}</span><span>&quot;, error), </span><span> }; </span><span>} </span></code></pre> <p>Similar to</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">use </span><span>std::fs::File; </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> greeting_file = File::open(&quot;</span><span style="color:#a3be8c;">hello.txt</span><span>&quot;).</span><span style="color:#96b5b4;">unwrap</span><span>(); </span><span>} </span></code></pre> <p>Or panic with error message</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">use </span><span>std::fs::File; </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> greeting_file = File::open(&quot;</span><span style="color:#a3be8c;">hello.txt</span><span>&quot;) </span><span> .</span><span style="color:#96b5b4;">expect</span><span>(&quot;</span><span style="color:#a3be8c;">hello.txt should be included in this project</span><span>&quot;); </span><span>} </span></code></pre> <p>In all these cases, its YOU, who asked the program to crash. Of course, this isn't any better than C++ yet.</p> <h3 id="matching-on-various-errors">Matching on various errors</h3> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">use </span><span>std::fs::File; </span><span style="color:#b48ead;">use </span><span>std::io::ErrorKind; </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> greeting_file_result = File::open(&quot;</span><span style="color:#a3be8c;">hello.txt</span><span>&quot;); </span><span> </span><span> </span><span style="color:#b48ead;">let</span><span> greeting_file = </span><span style="color:#b48ead;">match</span><span> greeting_file_result { </span><span> Ok(file) =&gt; file, </span><span> Err(error) =&gt; </span><span style="color:#b48ead;">match</span><span> error.</span><span style="color:#96b5b4;">kind</span><span>() { </span><span> ErrorKind::NotFound =&gt; </span><span style="color:#b48ead;">match </span><span>File::create(&quot;</span><span style="color:#a3be8c;">hello.txt</span><span>&quot;) { </span><span> Ok(fc) =&gt; fc, </span><span> Err(e) =&gt; panic!(&quot;</span><span style="color:#a3be8c;">Problem creating the file: {:?}</span><span>&quot;, e), </span><span> }, </span><span> other_error =&gt; { </span><span> panic!(&quot;</span><span style="color:#a3be8c;">Problem opening the file: {:?}</span><span>&quot;, other_error); </span><span> } </span><span> }, </span><span> }; </span><span>} </span></code></pre> <p>Same thing with closures</p> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">use </span><span>std::fs::File; </span><span style="color:#b48ead;">use </span><span>std::io::ErrorKind; </span><span> </span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> greeting_file = File::open(&quot;</span><span style="color:#a3be8c;">hello.txt</span><span>&quot;).</span><span style="color:#96b5b4;">unwrap_or_else</span><span>(|</span><span style="color:#bf616a;">error</span><span>| { </span><span> </span><span style="color:#b48ead;">if</span><span> error.</span><span style="color:#96b5b4;">kind</span><span>() == ErrorKind::NotFound { </span><span> File::create(&quot;</span><span style="color:#a3be8c;">hello.txt</span><span>&quot;).</span><span style="color:#96b5b4;">unwrap_or_else</span><span>(|</span><span style="color:#bf616a;">error</span><span>| { </span><span> panic!(&quot;</span><span style="color:#a3be8c;">Problem creating the file: {:?}</span><span>&quot;, error); </span><span> }) </span><span> } </span><span style="color:#b48ead;">else </span><span>{ </span><span> panic!(&quot;</span><span style="color:#a3be8c;">Problem opening the file: {:?}</span><span>&quot;, error); </span><span> } </span><span> }); </span><span>} </span></code></pre> <h2 id="smart-pointer-box">Smart pointer - Box</h2> <pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() { </span><span> </span><span style="color:#b48ead;">let</span><span> b = Box::new(</span><span style="color:#d08770;">5</span><span>); </span><span> println!(&quot;</span><span style="color:#a3be8c;">b = </span><span style="color:#d08770;">{}</span><span>&quot;, b); </span><span>} </span></code></pre> <p>When <code>b</code> goes out of scope, the value stored on heap is also dropped automatically.</p> <p>further talk</p> <ul> <li>why making linked list is a pain <ul> <li>Cons type</li> </ul> </li> </ul> <h2 id="traits">Traits</h2> <p>Opposite to object orientedness</p> <p>Traits can be derived</p> <ul> <li><code>Debug</code> for detailed printing of a variable</li> <li><code>PartialEq</code> for comparing values with <code>==</code> or <code>!=</code></li> <li><code>Clone</code></li> </ul> If You Wake Up Beautiful Tomorrow... Snehit Sah [email protected] http://snehit.dev 2023-05-17T00:00:00+00:00 2023-05-17T00:00:00+00:00 https://snehit.dev/posts/if-you-woke-up-beautiful/ <p>What if you wake up beautiful tomorrow?</p> <p>You might not pick up your blush brush. You might not wear your lip gloss. You might not hold up your concealer. You might not...</p> <p>If only you were beautiful...</p> <p>If you wake up beautiful tomorrow, you might not spend hours finding new fashionable clothes every month. You might not head to the gym so often. You might stop consulting your dietitian.</p> <p>If only you were beautiful...</p> <hr> <p>If you stopped using cosmetics, the chemical industry would lose a major chunk of its revenue. The mineral industry could too experience a sudden shock, for some mineral salts and oxides are commonly used in cosmetics. Its also hurting the transportation business, because a lot of materials have actually travelled the world more than you.</p> <p>If you bought less clothes and cared less about keeping up with the trend, you're gonna be attacking everyone - the people growing natural fibres, the textile industry as a whole, millions of staff who work at outlets and the people leasing out commercial spaces for clothing brands.</p> <p>What if you didn't go to gym? Gym equipment has to be manufacured and transported. The raw material too is transported to factories before they're fashioned.</p> <p>You could bring so many industries down to their knees if you were beautiful.</p> <hr> <p>The next time you feel you don't look beautiful, think about all the ways capitalists want you to feel ugly. At present, the masses not feeling beautiful fuels many capitalists' profits.</p> <p>Advertisments are being meant to make you feel insecure about otherwise natural features about us. You wanna exercise because you like being fit? Go ahead. But don't pick up those barbells if the local gym banner makes you feel like shit for not having toned arms. Working out because of you fear isn't making you strong; its only reinforcing that you're weak.</p> <p>The industry isn't centered around genuine benefits. Rather, its weaponizing your fears to expolit you.</p> <p>What if you wake up beautiful tomorrow? You could be more mindful of what you're doing to yourself and how you're unwantingly part of a big capitalist cycle.</p> <hr> <p><small>I do not discourage people from seeking professional advice in case of visible issues caused by medical conditions.</small></p> Stop Talking To AI. Learn Talking To Humans Instead Snehit Sah [email protected] http://snehit.dev 2023-05-03T00:00:00+00:00 2023-05-03T00:00:00+00:00 https://snehit.dev/posts/learn-talking-to-humans/ <p>Ever since ChatGPT has taken over the news, social media cartoons have been blessed with a source of constant content. Guides about studying with ChatGPT, making it do your work, asking for help the right way etc etc are doing the rounds. Content creators have discovered a totally new goldmine to exploit.</p> <p>Crappy course constructors weren't much behind; because a flood of prompt engineering courses are a real thing now. Teaching <em>how</em> to ask an AI to get your work done. Thats so much deja vu for me. I used to learn how to be tactically polite to get other people to help me. Being professional and polite can lead you so ahead in life. However being able to talk to an AI to get your work done doesn't elevate you in the social ladder.</p> <p>So, amidst the ChatGPT prompt crafting courses, I propose an old school course.</p> <p>Presenting...</p> <h2 id="how-to-talk-to-humans-latest-2023-updated">How To Talk To Humans [Latest 2023 Updated]</h2> <p>This course takes us back to our roots and teaches us how to talk to other fellow humans!</p> <p>Having the right vocabulary, tone, pace and confidence can push you ahead of the crowd. This course is guaranteed to elevate you in your career and relationships.</p> <p>With decline in social and communication skills among humans ever since online spaces became common, being able to talk professionally is hailed as a rare quality. Get this course right now to make yourself a sought after personality!</p> <h3 id="why-you-should-take-this-course">Why you should take this course</h3> <p>This course has been crafted based on thousands of years of evidence. (Humans have been talking to each other all along)</p> <p>You should take this course if you want to</p> <ul> <li>learn how to craft your words to sound welcoming</li> <li>easily join conversations and make new friends</li> <li>learn about word choice to make a lasting impact</li> <li>become a more critical thinker and easily present thoughts</li> <li>persuade people more easily (including your boss/ manager)</li> <li>become more entertaining and attract attention</li> </ul> <p>Being able to speak with confidence and being articulate will undoubtedly make you a <a href="https://www.youtube.com/watch?v=2FTx7DV7sv8">powerful force irrespective of your profession</a>.</p> <h3 id="why-you-should-not-take-this-course">Why you should NOT take this course</h3> <p>For the sake of honest marketing, I must also draw a line for those for whom this course is not suitable. Don't take up this course if</p> <ul> <li>you prefer being vague and useless</li> <li>screen pleasures excite you more than human interactions</li> <li>you are comfortable living in a false sense of satisfaction, without any real success</li> <li>real human connections don't matter to you</li> <li>you never seen, heard, smelled or met a real communicator (<a href="https://genius.com/Eminem-8-mile-lyrics">yee</a>)</li> </ul> <h3 id="course-fee">Course fee</h3> <p>For the greater good and in interest of social service, I have made this course <strong>FREE OF COST</strong>!</p> <p>That means no matter where you are, who you are or what you earn, you can get this course without paying a single penny. Everyone can now learn all the secret skills.</p> <h3 id="course-structure-and-enrollment">Course structure and enrollment</h3> <p>JUST STOP TALKING TO CHAT GPT AND GO OUT. TALK TO REAL PEOPLE LMAO.</p> <p>Practice speaking. Read more, write even more. Lead discussions and constantly improve your speech.</p> <h2 id="on-a-serious-note">On A Serious Note...</h2> <p>...prompt engineering (or anything related to talking to computers) isn't leading you anywhere. Its one of the many fodder materials for creators and hypestars to publish garbage online. A miniscule subset is making their $$$ with these AI tools, influencing masses to pump their time and energy into delicate bubbles of technology.</p> <p>In general, please please please be immune to hype trains. The hype stars glorifying generative AI today will move on to something else when the craze dies out. Instead, focus more on evergreen skills and invest in yourself.</p> <hr> <p>Yes I know prompt engineering is a real discipline. But nothing justifies the hype.</p> <p>For anyone genuinely intereseted in knowledge (and not hype), I can suggest the <a href="https://www.promptingguide.ai/">Prompt Engineering Guide</a>.</p> <p>May 5, 2022 : <a href="https://www.youtube.com/watch?v=Unzc731iCUY">How to Speak</a> by Patrick Winston is a great video. Highly recommended.</p> Tech Roadmap (to Industrial Age) Snehit Sah [email protected] http://snehit.dev 2023-01-23T00:00:00+00:00 2023-01-23T00:00:00+00:00 https://snehit.dev/posts/roadmaps/ <p>We all start from zero. (not funny)</p> <p>And we all need <em>some</em> guidance.</p> <p>Nicey.</p> <p>Hit YouTube, and there are <strike>tech folks</strike> <em>influencers</em> <strike>trying</strike> <em>pretending</em> to help.</p> <p>Of course, they can't help bring out everyone's unique interests and guide. (after all, they're just uploading a pre recorded video). So its understood that they will give "general advice" and the viewers are supposed to cherry pick and adapt what they like.</p> <hr> <p>Not so easy.</p> <p><strike>Tech folks</strike> <em>Influencers</em> came up with the idea of roadmaps!</p> <h2 id="production-line">Production Line</h2> <p>The very glory of these <strike>tech folks</strike> <em>influencers</em> lies in the fact that their "solutions" are claimed to give guaranteed result and elevate you to the prime of your career. Unfortunately, there are 100k other viewers on the same video, being elevated up the same upside down staircase.</p> <p>Roadmaps feel like a production line.</p> <p><em>Do ABC, make X projects, follow this order of studying topics. Voila! You're now an industry ready Java programmer!</em></p> <p>The level of confidence exibhited by these <strike>tech folks</strike> <em>influencers</em> in their roadmaps tend to induce dormancy in the individuality of their viewers. Really, its not their fault. Viewers too are the blankest persons that they virtually worship a person whose goals are to milk out money instead of guiding.</p> <p>Worshipping doesn't help. People change. Their life goals change. Their income streams change. Their strategies change. A person giving legitimate advice last year could be just peddling stupidity this year. If they can change their boats, then why not you? Move on from stupid.</p> <h2 id="the-secret-to-being-successful">The Secret To Being Successful</h2> <p>Unfortunately, there's no secret. If I told you the secret, it won't be a secret anymore. A <strike>tech folk</strike> <em>influencer</em> sharing the secret publicly, with his/her 100k viewers is obviously not sharing a "secret".</p> <p>The only plain and clear <em>open</em> secret, since the oldest times has been to have a vision and follow it. Everything else falls under two categories</p> <ol> <li>Public knowledge that viewers never got because they didn't use right sources of information. And now a <strike>tech folk</strike> <em>influencer</em> is glorifying and sharing the same advice, with his/her excited speaking tone, uplifting music, cinematic presentation (and a sponsor).</li> <li>Things that a significant population never really tried, or those who tried know that there there are dark linings to the advice. Meaning that the success rate with that advice is very low, or worse, the sample size of people who tried that is too small. Or in other senses, there are darker sides to the strategy which the presenter doesn't tell you. (eg. this happens very often with trading advice where certain people tend to overglorify the possible gains from the market, without making you aware of the possible pitfalls)</li> </ol> <p>Following a "secret" that a hundred thousand others already know will only land you in the massive pile of industrially manufactured programmers.</p> <h2 id="what-about-the-roadmaps-evergreen-edition">What About The Roadmaps? (evergreen edition)</h2> <p>For obvious reasons, there are some set ways to learn stuff and get started with anything new. There are some tools that have to be learnt together. (eg. if you are wanting to get into devops, you gotta learn certain tools no matter what)</p> <p>There has to be a "learning path". Thankfully, these "paths" can be reliably gotten from sources better than those influencers. Thats not to say that totally abandon those influencers.</p> <p>Track back to the original law - anyone who's not in a one to one communication with you can only give you "general advice". Now its your task to cherry pick and adapt what you think is useful. Its your task to ensure you don't become an industrially manufactured personality. You can use <em>any</em> source to get your pieces of information, but its your task to take up out of the line projects and ventures that set you apart.</p> <p>Vet each piece of information and verify if it is real or sponsored!</p> Memories Snehit Sah [email protected] http://snehit.dev 2023-01-18T00:00:00+00:00 2023-01-18T00:00:00+00:00 https://snehit.dev/posts/memories/ <p>The young and fresh feeling of early teens, roaming the halls like the world was ours. We were grossly wrong, but it was fun. First time we caught a glimpse of the eyes that soothed our mind or the innumerous instances where we were the reason for someone's smile. All tucked away in a corner of our mind.</p> <p>Back then, none of us knew how much of it is gonna stay along. Everyday was a step in the future, leaving behind whatever happened earlier. Somewhere along, we broke our promises and secretly picked up bits and pieces. Never knowing where we hid all the dust and gold. Jacket's inside pocket or the jeans back pocket. It all flowed with our bodies and before we knew, became an inseparable part of us.</p> <p>Smiles aren't the same anymore. Glances turn into wilful gazes. No longer a flower blooms without purpose. Every step is an endeavour to write another page in this everflowing diary. Craving for the extra minute and an extra look into my eyes. Sparing a moment in time and giving it a name. This moment belongs to you. This moment belongs to us.</p> <p>The less I smile, the better I smile when I do. Just when it all feels right, the stage is scattered; curtains draw on. Crowd disperses. Its time for the next act. The symphony changes. Actors switch. Can't have it all. Can't have everyone. Can't have everyone's smiles forever. Can't have everyone's gaze forever. Except memories.</p> <p>The world wasn't mine. I can carry along only a piece of this beauty. One seed. One flower. One season. All else burns down to bits and pieces I scramble for.</p> <p>Jacket's inside pocket or the jeans back pocket. More gold accumulates, hidden with the dust. A new walk. New smiles. And a longing to explain the older smiles that how much they matter even if they don't see my eyes anymore.</p> Merit Finding in Broken Systems Snehit Sah [email protected] http://snehit.dev 2022-11-16T00:00:00+00:00 2022-11-16T00:00:00+00:00 https://snehit.dev/posts/merit-finding-in-broken-systems/ <p>This morning I came across a tiny newspaper article telling the story of a man who secured education while battling financial hardships. He had to put <em>all</em> his family's savings to get coaching for clearing exam to get into an engineering college. Later his family even sold a couple of belongings to pay for college in initial days.</p> <p>In 2011, he secured a job at an IT firm. As of writing this blog, he has risen the ranks and still working there.</p> <p>Well and good. There's lots of hardships here. Raw daredevilry involved to push him to pursue engineering when financial issues were the reason why his elder brother couldn't continue his studies.</p> <p>Now go, <em>get inspired</em>!</p> <p>Thats the current state of public systems. We are celebrating struggles of people who stood against the odds to rise up. We are glorifying their achievements to ensure that the youth doesn't question this system, and instead braces up to be more resillient. We find satisfaction in knowing that we "made through" a bad time.</p> <p>Never do we question why we had to face it in the first place.</p> <p>This is the first year when CUET is being used to admit students to Delhi University. Mishaps have already been reported. The pathetic state of engineering entrance exams are not unknown to any student remotely related to the science stream. Cost of professional education is rising rapidly even in public institutions.</p> <p>Glorifying the struggles of financially weak families and presenting it as an example to promote others to be resillient is only making us "used to" the crap pile. <em>"Hey, look. Its normal to blow up your entire savings to educate your child. This family did it. Why not you?"</em></p> <p>The same newspaper could have carried a page long article on the miseries of students having to drop out at various stages in their education. We need more public welfare schemes to guarantee education (and employment).</p> <p>I'm rocking for change. Which is often equated with stepping into the parliament and boot mocking a bunch of politicians.</p> <p>Nah!</p> <p>Change happens in classrooms. But we've long lost them.</p> A Cringe Love Story Snehit Sah [email protected] http://snehit.dev 2022-11-02T00:00:00+00:00 2022-11-02T00:00:00+00:00 https://snehit.dev/posts/cringe-love-story/ <p>You say you watch garbage content because the creator publishes it.</p> <span id="continue-reading"></span> <p>Creator says they make garbage content because you watch it.</p> <p>Ain't this a match made in heaven?</p> <p><em>*cringe factor explodes</em></p> Updates On Space Actions Merge Request- GSoC'22 post #15 Snehit Sah [email protected] http://snehit.dev 2022-09-04T00:00:00+00:00 2022-09-04T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/updates-on-space-action-mr/ <p>I created a merge request to submit my additions for Space Home and Space Creation/ Editing functionality. The merge request can be found <a href="https://invent.kde.org/network/neochat/-/merge_requests/509">here</a>.</p> <p>This merge request recieved a lot of helpful suggestions by Carl Schwan and Jan Bidler. I tried implementing a lot of them.</p> <p>There were a couple of UI fixes. Non privileged accounts were restricted from accessing options to edit child rooms of Spaces on UI.</p> <p>There were some syntax related changes too.</p> <p>Functionality wise, I will be creating a new list model for the child room editor. It will contain the rooms user is part of as well as rooms that are children of Space. I also have to set up connections to update Space home page whenever changes to Space settings are made.</p> <p>This is the final post for Google Summer of Code 2022. I will continue to contribute to NeoChat, and to other KDE projects. I will push updates to the open merge request contribute further code or bug fixes.</p> Adding Room To Space- GSoC'22 post #14 Snehit Sah [email protected] http://snehit.dev 2022-08-26T00:00:00+00:00 2022-08-26T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/adding-room-to-space/ <p>I have implemented adding room to a Space.</p> <p>I needed help from Tobias with it. I wanted to send <code>m.space.child</code> room event to a Space, but didn't know the right way to do it. Tobias suggested that I use the following function</p> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span>SetRoomStateWithKeyJob* </span><span style="color:#8fa1b3;">setState</span><span>(</span><span style="color:#b48ead;">const</span><span> QString&amp; </span><span style="color:#bf616a;">evtType</span><span>, </span><span> </span><span style="color:#b48ead;">const</span><span> QString&amp; </span><span style="color:#bf616a;">stateKey</span><span>, </span><span> </span><span style="color:#b48ead;">const</span><span> QJsonObject&amp; </span><span style="color:#bf616a;">contentJson</span><span>); </span></code></pre> <p>Here, <code>contentJson</code> will have the room event data.</p> <p>The function call I used for removing a room from Space is</p> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span>connection-&gt;</span><span style="color:#bf616a;">callApi</span><span>&lt;SetRoomStateWithKeyJob&gt;(spaceId, &quot;</span><span style="color:#a3be8c;">m.space.child</span><span>&quot;, roomId, </span><span style="color:#bf616a;">QJsonObject</span><span>{}); </span></code></pre> <p>Similarly, the function call I used to add room to Space is</p> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span>connection-&gt;</span><span style="color:#bf616a;">callApi</span><span>&lt;SetRoomStateWithKeyJob&gt;(spaceId, &quot;</span><span style="color:#a3be8c;">m.space.child</span><span>&quot;, roomId, </span><span style="color:#bf616a;">QJsonObject</span><span>{{&quot;</span><span style="color:#a3be8c;">via</span><span>&quot;, {connection-&gt;</span><span style="color:#bf616a;">homeserver</span><span>().</span><span style="color:#bf616a;">toString</span><span>()}}}); </span></code></pre> <p>Its all well and good, except that adding room to Space doesn't work!</p> <p>I asked about this to Tobias on our call. He pointed out that <code>{connection-&gt;homeserver().toString()}</code> should be written as <code>QJsonObject{connection-&gt;homeserver().toString()}</code>.</p> <p>So, finally the call becomes <code>connection-&gt;callApi&lt;SetRoomStateWithKeyJob&gt;(spaceId, "m.space.child", roomId, QJsonObject{{"via", QJsonArray{connection-&gt;homeserver().toString()}}});</code></p> <p>With this, one can add or remove rooms. This feature is being added to the Child Rooms editor in Space Settings.</p> Creating Spaces In NeoChat- GSoC'22 post #13 Snehit Sah [email protected] http://snehit.dev 2022-08-18T00:00:00+00:00 2022-08-18T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/creating-spaces-in-neochat/ <p>In this post I'm recording how I implement creating Spaces via NeoChat.</p> <p>Creating the UI front was rather easy, since I used the same dialog as that for creating room. We could have both room and space creation in same dialog because of how similarly they're represented in Matrix. (Space is just room with one extra event)</p> <p><img src="/images/space-creation.png" alt="space creation" /></p> <p>On the functionality side, I had to set the <code>m.room.type</code> key to <code>m.space</code> upon creating the room. This was done by setting <code>creationContent</code> JSON value to the same.</p> Polishing Spaces Horizontal Bar And Space Home- GSoC'22 post #12 Snehit Sah [email protected] http://snehit.dev 2022-08-12T00:00:00+00:00 2022-08-12T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/polishing-spaces-horizontal-bar-and-home/ <p>Tobias texted that the SpaceHierarchyCache class worked as expected. So I added that to the open merge requst.</p> <p>I have also been working on the Space home page.</p> <p><img src="/images/space-home-aug-11.png" alt="space home" /></p> <p>This currently allows the following</p> <ul> <li>viewing all rooms in a space</li> <li>joining rooms</li> <li>opening joined rooms</li> <li>leaving space</li> </ul> <p>@miepee took the time to give me many suggestions relating to user experience. I tried to implement most of the suggestions they shared.</p> <p>Another minor thing I changed is that SpaceHierarchyCache is now a singleton in QML.</p> <p>Carl helped me with the long standing issue with layout by sending a patch that brought Space icons to middle of the layout. (Thanks!)</p> Separating Space Hierarchy Cache to New Class - GSoC'22 post #11 Snehit Sah [email protected] http://snehit.dev 2022-08-05T00:00:00+00:00 2022-08-05T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/separating-space-hierarchy-class/ <p>While testing my merge request, Tobias spotted that NeoChat was making multiple requests to the <code>/hierarchy</code> API endpoint. The requests were actually being spammed to the server.</p> <p>So I was suggested to separate the Space hierarchy caching functionality to a separate class itself.</p> <p>The work was mostly about refactoring. Code was already existing in a different class. I moved it to the new <code>SpaceHierarchyCache</code> class and edited it to glue in properly.</p> <p><code>getRoomListForSpace()</code> in <code>SpaceHierarchyCache</code> accepts a space id, and returns a list of rooms id that belong to the space. This function is exposed in QML and used to populate <code>SortFilterRoomListModel:: m_activeSpaceRooms</code> whenever user clicks a Space icon.</p> <p>Rest of the implementation is mostly similar to what was earlier scattered through <code>SortFilterRoomListModel</code>.</p> <p>The code is currently on a separate branch on my fork so that my mentors can check if it looks and works right. If they say its fine, I'll add the code to my open merge request.</p> <p>PS. Its my birthday today :)</p> Space Hierarchy Caching Finally Works - GSoC'22 post #10 Snehit Sah [email protected] http://snehit.dev 2022-07-24T00:00:00+00:00 2022-07-24T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/space-hierarchy-cache-finally-works/ <p>After a lot of ups and downs, I finally got Space hierarchy caching to work on NeoChat.</p> <p>The commit is <a href="https://invent.kde.org/network/neochat/-/merge_requests/479/diffs?commit_id=6d227a02fcc95feb9e889fe489f4a55851e2ec91">here</a>.</p> <p>I told in my <a href="https://snehit.dev/posts/kde/gsoc-22/be-careful-with-signal-slots/">yesterday's post</a> about how a silly error on my part was not letting caching work as expected.</p> <p>Now, I have invkoed <code>cacheSpaceHierarchy()</code> once when <code>SortFilterRoomListModel</code> is initialized.</p> <p><code>populateSpaceHierarchy()</code> accepts an additional parameter to decide if the UI needs to be updated. According to current logic, the UI shoudn't be updated when the caching happens as a part of class initialization. It must be updated only when user clicks on a Space icon.</p> Be Careful With Signal Slots - GSoC'22 post #9 Snehit Sah [email protected] http://snehit.dev 2022-07-23T00:00:00+00:00 2022-07-23T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/be-careful-with-signal-slots/ <p>Here's something interesting thing I stubled across today. (more like, struggled with for a day and half) This might be something obvious to regular Qt programmers, but I'm not a professional.</p> <p>In my last post I told how Tobias helped me get <code>cacheSpaceHierarchy()</code> function working as expected. The fix was easy. That doesn't mean I'll take half a minute to code and commit.</p> <p><code>cacheSpaceHierarchy()</code> was being called correctly as expected. But now this function stopped functioning. It worked until two days back when it was being called at the wrong time. But today when I call it <em>at the right place</em>, it decides it won't work.</p> <p>Whats funny to me is that the reason behind this malfunction was similar to the problem last week.</p> <p>I used the following snipped to wait for a room to load and then populate its room list if its a space.</p> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#bf616a;">connect</span><span>(neoChatRoom, &amp;Room::baseStateLoaded, neoChatRoom, [</span><span style="color:#bf616a;">this</span><span>, neoChatRoom, connection]() { </span><span> </span><span style="color:#b48ead;">if </span><span>(neoChatRoom-&gt;</span><span style="color:#bf616a;">isSpace</span><span>()) { </span><span> </span><span style="color:#bf616a;">this</span><span>-&gt;</span><span style="color:#bf616a;">populateSpaceHierarchy</span><span>(connection, neoChatRoom-&gt;</span><span style="color:#bf616a;">id</span><span>(), </span><span style="color:#d08770;">false</span><span>); </span><span> } </span><span>}); </span></code></pre> <p>The issue, you ask? <code>&amp;Room::baseStateLoaded</code> signal is already been fired before this connection is made and as a result, the inner block is never executed.</p> <p>Solution?</p> <p>Just check if relevant data is loaded. If yes, use that data. If not, then set up the connection and wait for the data to be loaded.</p> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#b48ead;">if </span><span>(neoChatRoom-&gt;</span><span style="color:#bf616a;">isSpace</span><span>()) { </span><span> </span><span style="color:#bf616a;">this</span><span>-&gt;</span><span style="color:#bf616a;">populateSpaceHierarchy</span><span>(connection, neoChatRoom-&gt;</span><span style="color:#bf616a;">id</span><span>(), </span><span style="color:#d08770;">false</span><span>); </span><span>} </span><span style="color:#b48ead;">else </span><span>{ </span><span> </span><span style="color:#bf616a;">connect</span><span>(neoChatRoom, &amp;Room::baseStateLoaded, neoChatRoom, [</span><span style="color:#bf616a;">this</span><span>, neoChatRoom, connection]() { </span><span> </span><span style="color:#b48ead;">if </span><span>(neoChatRoom-&gt;</span><span style="color:#bf616a;">isSpace</span><span>()) { </span><span> </span><span style="color:#bf616a;">this</span><span>-&gt;</span><span style="color:#bf616a;">populateSpaceHierarchy</span><span>(connection, neoChatRoom-&gt;</span><span style="color:#bf616a;">id</span><span>(), </span><span style="color:#d08770;">false</span><span>); </span><span> } </span><span> }); </span><span>} </span></code></pre> <p>This works, because <code>neoChatRoom-&gt;isSpace()</code> can be <code>true</code> <em>only</em> if room's base state is loaded.</p> <p>There is one potential issue though. This will set up a good number of unused connections. I'll have to discuss it with my mentors and get their views if there's a better way to accomplish this goal.</p> Getting Stuck and Unstuck - GSoC'22 post #8 Snehit Sah [email protected] http://snehit.dev 2022-07-21T00:00:00+00:00 2022-07-21T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/getting-stuck-and-unstuck/ <p>I made progress - on getting stuck in my work.</p> <p>In my meet with my mentors last week, we decided I'll work on the Space home page while finalizing the <a href="https://invent.kde.org/network/neochat/-/merge_requests/479">merge request</a> I had opened.</p> <h2 id="getting-space-home-page-on-stack">Getting Space Home Page on Stack</h2> <p>I wrote a new QML file, which I later realised I couldn't figure out an easy method for passing data to. So my Space home page was populated with hardcoded dummy data. (lorem ipsum 👍)</p> <p><img src="/images/space-home.png" alt="space-home" /></p> <p>So, to view how the UI looks, I'll need to view it, right? Yes of course. But the problem here was that once I added the Spce home page on page stack on right pane of NeoChat, I couldn't close it. Neither could I open any room.</p> <p>Removing the offending piece of code should fix it, right? Yes?</p> <p>NO!</p> <p>Something about the cache that NeoChat stores to restore state on startup was not letting me exit the Space home page. Too bad. Thankfully Tobias told me <em>which</em> cache file to delete and I was back up running.</p> <h2 id="caching-space-hierarchy-on-startup">Caching Space Hierarchy on Startup</h2> <p>I wrote a function <code>SortFilterRoomListModel ::cacheSpaceHierarchy()</code> that is supposed to be fired when the class constructor is called and will query <code>/hierarchy</code> for each space to cache the list of their child rooms. This caching will let NeoChat instantly update UI when filtering rooms. SortFilterRoomListModelt they were the logs I expected so why should I cry. Room lists were being cached.</p> <p>Next problem was that I couldn't access the cached room list while filtering. The map was empty always. Why? I didn't know. I did my old school debugging i.e. sticking up print statements all over the place. Some <code>qInfo()</code> later, I got to realize there are not just two instances of <code>SortFilterRoomListModel</code>, but there are actually THREE. Nice. Whats worse is that for the third one, the cache function wasn't being called at all and this third one is what was presented to user.</p> <p>The issue was too peculiar to me, and will all evidences gathered, it seemes like quite a long issue to explain over chat to my mentors. Thankfully, that was two days back; today I had a call with Tobias, who cleared the air of mystery.</p> <h2 id="untangling-myself">Untangling Myself</h2> <p>Tobias told me there were indeed multiple instances of <code>SortFilterRoomListModel</code> which I shouldn't care about. What I <em>should</em> care about is that the instance shown to the user isn't working as expected. He took a look at my code and traced down the issue to something I personally wouldn't have suspected.</p> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#bf616a;">connect</span><span>(&amp;Controller::</span><span style="color:#bf616a;">instance</span><span>(), &amp;Controller::activeConnectionChanged, </span><span style="color:#bf616a;">this</span><span>, [</span><span style="color:#bf616a;">this</span><span>]() { </span><span> </span><span style="color:#bf616a;">cacheSpaceHierarchy</span><span>(); </span><span>}); </span></code></pre> <p>This is how I was calling <code>cacheSpaceHierarchy()</code>. Looks fine, EXCEPT that this connection is made only after the signal we're waiting for (<code>Controller ::activeConnectionChanged</code>) has already been fired. The signal doesn't fire again and caching function is never called. The solution was to add another call to <code>cacheSpaceHierarchy()</code> outside of this connection.</p> <p>Such an easy fix.</p> <p>About my problem with not being able to exit Space home page, Tobias suggested I try pushing page onto <code>pageStack.layers</code> instead of <code>pageStack</code> like I was doing.</p> <p>Certain things are easy, but I end up complicating them for no reason.</p> Review and Updates for Merge Request - GSoC'22 post #7 Snehit Sah [email protected] http://snehit.dev 2022-07-14T00:00:00+00:00 2022-07-14T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/merge-request-review/ <p>On July 9th, I created a merge request to submit all the work I did to add Space bar. The first issue was that CI builds failed because CI image has libQuotient 0.6 which doesn't support the Space <code>/hierarchy</code> call. As suggested by Tobias, getting around it was easy, as I could guard relevant code inside <code>#ifdef QUOTIENT_07</code>. This got the CI build passing.</p> <p>Next there were quite a few code improvements suggested by Tobias and Carl. I'll list down some important changes.</p> <p><code>NeoChatRoom::isSpace()</code> no longer uses a handmade json parsing system to determine if a room is Space or not. Instead, it now relies on <code>RoomCreateEvent::roomType()</code> for the same.</p> <p>Empty string comparisons have been replaced with a <code>.empty()</code> method call.</p> <p>The code to fetch children of a Space was being reused, so it has now been separated in <code>SortFilterRoomListModel::populateSpaceHierarchy</code>.</p> <p>There are lot more suggestion I recieved on my merge request. They can be viewed here -&gt; <a href="https://invent.kde.org/network/neochat/-/merge_requests/479">https://invent.kde.org/network/neochat/-/merge_requests/479</a></p> <p>During this week I also decided that I would work on the Space landing page, but due to sudden family issues, I'm running late on that. I'll make up for it in coming week.</p> Improving Space Bar Functionality - GSoC'22 post #6 Snehit Sah [email protected] http://snehit.dev 2022-07-07T00:00:00+00:00 2022-07-07T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/improving-space-bar-functionality/ <p>On my weekly call with mentors today, I showed them how my Space bar works and I recieved some suggestions.</p> <p>One point of discussion was that clicking on a Space icon for first time resulted in noticeable delay before the UI was updated with filtered room list. The cause was traced to the latency introduced by <code>/hierarchy</code> api call.</p> <p>The solution we agreed on was to cache the list of child rooms of each space. So along with <code>m_activeSpaceRooms</code>, I created a <code>QMap</code> named <code>m_spaceHierarchy</code> which uses id of a Space as key, and its value being a list of child rooms. This cache is persistent as long an NeoChat is running.</p> <p>We also decided we could prefetch the child rooms for all Spaces on startup. While this could potentially create many api requests at once, it seemed unlikely that a user would be part of so many Spaces so as to spam the server with <code>/hierarchy</code> calls. Still, as a future addition, I would like to try limiting <code>/hierarchy</code> calls, and instead queue them.</p> <p>The prefetch is done when SortFilterRoomListModel is initialised, which doesn't seem like the right time to do it - because by that time, Connection is not established, and the prefetch function fails to result in a segfault.</p> <p>I have to take a look into this and come up with a workaround. Meanwhile, other features do work.</p> Making Spaces Bar Work - GSoC'22 post #5 Snehit Sah [email protected] http://snehit.dev 2022-06-27T00:00:00+00:00 2022-06-27T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/making-space-bar-work/ <p>During past few days, I have worked on adding functionality to the Space bar. In my last post I described how I got the UI finally working. The next milestone is to have rooms filtered based on the Space user clicks on.</p> <p>The <code>/hierarchy</code> call was recently added in libQuotient 0.7. This gives a list of all rooms that are children of a given Space.</p> <p><a href="https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv1roomsroomidhierarchy">link to spec</a></p> <p>Since the fitering of room list happens in class <code>SortFilterRoomListModel</code>, I added a function in there, named <code>setActiveSpaceRooms</code>. What this function does is to take a Space id as parameter and find all rooms which are children of given Space, via the <code>/hierarchy</code> api call. Once the list of rooms have been found, their id are stored in a <code>QVector</code>, named <code>m_activeSpaceRooms</code>. Then I updated <code>SortFilterRoomListModel::filterAcceptsRow</code> to filter rows based on the value of this vector. If vector is empty, it shows all rooms, filtered on search query (i.e. the original behaviour). If <code>m_activeSpaceRooms</code> vector is not empty, then the id of rooms there are used to filter out rooms from model, along with search terms (if any).</p> <p>The header of list view has a row layout, with two elements - a home button and a list of Spaces. Home button resets the Space filter and shows all rooms like it does normally. Clicking on a Space icon filters out to show only those rooms which belong to the Space.</p> <p>Here are two screenshots of NeoChat, with the filtering feature in action.</p> <p><img src="/images/space-preview-1.png" alt="NeoChat filtering based on a Space" /></p> <p><img src="/images/space-preview-2.png" alt="NeoChat filtering based on a Space" /></p> <p>I'll be making some improvements here and there and cleaning the code.</p> Adding Spaces Horizontal Bar to NeoChat (Repeat?) - GSoC'22 post #4 Snehit Sah [email protected] http://snehit.dev 2022-06-24T00:00:00+00:00 2022-06-24T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/adding-spaces-list-pt-2/ <p>In my last post I described how I added my Spaces horizontal bar as a header of ScrollingPage. It worked fine for most part, except for the fact that I didn't reserve space for itself and was being overlapped by the room list.</p> <p>After discussing it with my mentors, we decided it would be easier to put that as a header to room list itself. That <em>did</em> work, but the layout dimensions were all wrong. Took me some 2-3 days and GammaRay to figure out what all was wrong and make it work.</p> <p>To get this to work, I created a new class <code>SortFilterSpaceListModel</code>. The earlier method of filtering Spaces by using room list as source and hiding normal rooms didn't result in the cleanest UI. It would leave extra spaces here and there (probably from paddings or margins of invisible elements).</p> <p>By creating a separate class for Spaces altogether, we now have more control over the model and can extend it in future if needed.</p> <p><img src="/images/space_bar.png" alt="NeoChat with Space Bar" /></p> Adding Spaces Horizontal Bar to NeoChat - GSoC'22 post #3 Snehit Sah [email protected] http://snehit.dev 2022-06-17T00:00:00+00:00 2022-06-17T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/adding-spaces-list/ <p>Hi!</p> <p>This is my third post during Google Summer of Code 2022.</p> <span id="continue-reading"></span> <p>During the first week of coding period, I tried my hands at adding a horizontally scrolling bar on top of room list, which would show user's joined spaces.</p> <p>The first ended in failure, because I was used to using <code>setContext()</code> for controlling QML via C++. NeoChat uses a different method of exposing classes though. Tobias helped me understand the method NeoChat uses.</p> <p>I gave the thing another try and got some success this time.</p> <p>I added a new role in roomlistmodel, named <code>IsSpaceRole</code>. This calls the function <code>isSpace()</code> from neochatroom. The function checks room creation event and determines if a given room is space or not.</p> <p>On the UI part, there was a horizontal scrolling UI module used elsewhere, which I reused.</p> <p>When it came to integrating the UI component into actual Room List Page, things again took a hit. My first try was to wrap Room List and Space List into a Row layout. That made the Room List not show rooms, and only the categories.</p> <p><img src="/images/neochat-old-1.png" alt="neochat-old" /></p> <p>I was suggested by Carl to put Space list as header of the Scrollable Page. Doing so gave better result, apart from the fact that Space list now overlaps with Room List.</p> <p><img src="/images/neochat.png" alt="neochat" /></p> <p>Tobias suggested that specifying height of the Space List should fix that. I also need to fix the issue of invisible rooms taking up width in Space list.</p> <p>For the coming week, I plan to implement room filtering, such that when user clicks on a certain Space, then only the room corresponding to that Space are visible.</p> Community Bonding GSoC 2022 - post #2 Snehit Sah [email protected] http://snehit.dev 2022-06-10T00:00:00+00:00 2022-06-10T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/community-bonding/ <p>Hi!</p> <p>This is my second post during Google Summer of Code 2022.</p> <span id="continue-reading"></span> <p>GSoC community bonding period ends tomorrow.</p> <p>During this time, I have tried playing around with LibQuotient by writing simple C++ apps to show details from a user's account. (joined rooms, filtering out spaces etc)</p> <p>On NeoChat, I tried adding UI element to show user's spaces, which <em>certainly</em> didn't go well. The ListView would not show a scroll bar, no matter what. I faced another setback when I realized the code didn't use <code>setContext</code> to control UI (thats the way I'm accustomed to doing it).</p> <p>This week, Tobias helped me out with these technical things over a call. I'm trying to implement them.</p> <p>With the actual coding period starting in 2 days, I hope to show up tangible work.</p> Beginning with Google Summer of Code 2022 - post #1 Snehit Sah [email protected] http://snehit.dev 2022-06-03T00:00:00+00:00 2022-06-03T00:00:00+00:00 https://snehit.dev/posts/kde/gsoc-22/hello-world/ <p>Hi!</p> <p>This is my first post during Google Summer of Code 2022.</p> <span id="continue-reading"></span> <p>I will be working on adding Spaces support to NeoChat. My mentors for the project are Carl Schwan and Tobias Fella. I have had two calls with them already, and gotten clarity on how I can get started with the work.</p> <p>I will be posting blogs regularly on my website. To follow my progress, see my posts on my <a href="https://snehit.dev/posts/kde/gsoc-22/">blog</a>.</p> Twentieth Winter and French Konnektion Snehit Sah [email protected] http://snehit.dev 2022-04-14T00:00:00+00:00 2022-04-14T00:00:00+00:00 https://snehit.dev/posts/kde/sok-2022/rename-kde-connect-to-kde-konnekt/ <p>Ohayo Gozaimosu!</p> <p>This is going to a slightly informal post about my SoK experience. If you're looking for my status updates, the sixth and final status update was posted <a href="https://snehit.dev/posts/kde/sok-2022/final-update/">here</a>.</p> <h2 id="my-french-konnekt">My French KonneKt</h2> <p>Back during 2013 - 2015, I studied French at school. That was the first touch with this language for most students, as a result we did not have any serious texts in our coursebook. All texts were related to a French person/ couple/ family going out to the beach or monument or for picnic or something like that. For three years I studied that.</p> <p>The net learning that a young Snehit had from those year was that <em>the French are really cool people!</em> Had I continued studying French, I would have been exposed to more serious texts, but I simply had to drop the subject when they got more focused on irregular verbs.</p> <h2 id="my-twentieth-winter">My Twentieth Winter</h2> <p>So what happened during the twentieth winter of my life? Of course, I had caught a cold after Christmas, which meant that my laptop and PC could finally get some rest. It also meant that I would be late to the join the KDE folks.</p> <p>On 30th December 2021, I joined the KDE Flatpak Matrix channel, only to see that some potential contributors for the project have already introduced themselves. My health was in no mood to get to work, so I went back to sleep.</p> <p>On 9th January 2022, I finally decided I was back in my usual high. Quickly checked the groups and <em>oh my cat!</em> Everyone had already gotten on to work. I scroll up the messages and find that three days prior to that, a cool sounding person had tagged four people and given them some instructions on how they could get started with the work. I felt I was <em>far off</em>, so I decided I could just help out the other contributors if they face roadblocks. That was the tiniest sweet thing a cake could do. And I do think I could help out a fine enthusiastic person on the channel.</p> <h2 id="french-konnekt-pt-2">French KonneKt Pt. 2</h2> <p>I was casually looking about the cool person I mentioned earlier, Timothée Ravier. YouTube seemed to have some videos by this person and <em>wait what</em>, he was speaking French???</p> <p>I <em>really</em> needed to work with this cool person. I mean I wasn't expecting to virtually visit Le Louvre with him, but at least I could flex that I can pronounce the French 'r'!</p> <p>So I speed run learning how to package as Flatpak. As I have mentioned many times already, I have experience in that, so it was rather smooth for me.</p> <p>Timothée has been very helpful during our chats. Patiently listens to everything I say, while I go haywire telling him <em>I did this, I broke that, I'll do this, I won't do that</em>. I might just switch to an AZERTY keyboard, because I type his name too often these days and have to copy paste that é every time.</p> <h2 id="getting-to-work">Getting to Work</h2> <p>Since I did not have classes in first 2-3 weeks of SoK, I speed ran my project (typical of me). A good number of applications were submitted to Flathub.</p> <p>Next I tried reinventing the wheel, because I have a history of programming in Rust. As usual, I fell back to using a Python script. Flatpak External Data Checker got the work done, even though it did produce unexpected output at times.</p> <p>Over on to the CI stuff, I wrote and rewrote^7 the build script. It not yet perfect, but I'll get to it very soon.</p> <p>One potentially good thing to happen with me was that I started using Twitter. Now I'm more in sync with the abbreviations people use these days, thanks to the character limit. I hope they bring out the edit feature soon, and make the character limit 100x times longer so that long worded people like me feel at home there, but first I'm gonna petition to rename KDE Connect to KDE KonneKt.</p> <h2 id="what-i-learnt">What I Learnt</h2> <ul> <li>Packaging</li> <li>Not running <code>rm -rf</code> out of context (I once deleted my build directory and then had to rebuild many KDE apps again)</li> <li>Being on time for online meetings (other's time is important too)</li> <li>Debating why JSON is better than YAML</li> </ul> <h2 id="conclusions">Conclusions</h2> <p>French people are cool. So is whole of the KDE Community.</p> Status update: Wrapping Up and Beyond the Event - post #6 Snehit Sah [email protected] http://snehit.dev 2022-04-13T00:00:00+00:00 2022-04-13T00:00:00+00:00 https://snehit.dev/posts/kde/sok-2022/final-update/ <p>Hello!</p> <p>This is my final status update for Season of KDE 2022. There's news on the Flatpak CI builds and my plans for after this event.</p> <span id="continue-reading"></span><h2 id="flatpak-ci-builds">Flatpak CI Builds</h2> <p>With help and suggestions from my mentor, Timothée Ravier, I got the CI script finalized from our side. I created a <a href="https://invent.kde.org/sysadmin/ci-utilities/-/merge_requests/17">pull request</a> on the CI repository.</p> <p>I initially didn't know that the images on KDE infra are not ephemeral. As a result, I spent a great deal of time on slimming down the Docker image I was using. I started off with an Arch Linux image, which I later switched to Fedora. The script itself went many changes before it was submitted for review. Initially it didn't have flexibility with regards to location of manifest and could only build apps requiring the latest KDE platform. It was updated over and over until we were satisfied.</p> <p>After I submitted the script for review, Ben Cooksley gave a lot of useful suggestions. The script is now much more flexible with regards to manifest location. It can dynamically decide which platform and SDK to use.</p> <p>The pull request hasn't been merged, but I will get it done in due time.</p> <h2 id="fedc-on-kde-invent">FEDC on KDE Invent</h2> <p>I also planned to have an automatic updater on our master Flatpak repository. While the overall idea of how this is to be accomplished has been clear from the very beginning, the actual implementation however has gone many changes. For now, it is a <a href="https://gitlab.com/flyingcakes/kde-flathub-master/-/blob/master/updater.sh">shell script</a> which I wanted to move to Python. I <em>actually</em> did rewrite it in Python - and I wasn't yet satisfied.</p> <p>During the review of my pull request for Flatpak CI script, Ben proposed that we have each manifest in individual application repositories. A side effect is that the script will need to be modified a little bit.</p> <p>I've kept the script on hold for now, although the basic bits are set up. I'll just need to plug in the final stuff once we decide where the manifests are going to be placed.</p> <h2 id="beyond-sok">Beyond SoK</h2> <p>Season of KDE has been a great experience for me. I got to know some very cool people. I got to learn cool things. I did cool things. I've been close to open source and SoK was a great booster to my experience.</p> <p>I'll be taking a break for ~3 weeks to get done with my exams. When I return, I'll fast track the CI stuff that is currently on draft. I'm still available on the KDE Matrix and email.</p> <p>Bye bye!</p> Status update: Adding CI Pipelines on GitLab - post #5 Snehit Sah [email protected] http://snehit.dev 2022-03-29T00:00:00+00:00 2022-03-29T00:00:00+00:00 https://snehit.dev/posts/kde/sok-2022/adding-ci-on-gitlab/ <p>Hey there!</p> <p>This is my fifth status update for Season of KDE 2022.</p> <p>This time, I have updates on the automation side of things. I got a preliminary version of the required GitLab pipelines working.</p> <span id="continue-reading"></span><h2 id="pipeline-for-updating-manifests">Pipeline for Updating Manifests</h2> <p>I got my hands dirty with Docker and added the Flatpak External Data Checker image over on <a href="https://quay.io">Quay</a>. The image was used over on my Gitlab repositories. This let me run "actions", similar to what we have on GitHub, but on GitLab too. Since we're not relying on the official FEDC image, I can control what all goes into the image and add extra dependencies that would be required. (like curl)</p> <p>Currently, the script is in bash. I plan to port it to Python, as it will be much easier to maintain and work with.</p> <p>The script is expected to loop through all manifests in the repository and run FEDC on each one of them while capturing FEDC output to detect which packages have been updated. It then does some cleanup and sorts it to get the final list. With all the changes, it will finally commit and create a merge request over on the repository. To avoid creating multiple merge requests for the same set of updates, the script will check if there is an existing merge request already. To help in this, it adds a short hash in the merge request title, which lets it cross-check the set of updates and decide whether to create a new merge request or not.</p> <p>The repository can be found here -&gt; <a href="https://gitlab.com/flyingcakes/kde-flathub-master">https://gitlab.com/flyingcakes/kde-flathub-master</a>. Actual update script is in the <code>updater.sh</code> file in this repo.</p> <h2 id="pipeline-for-application-ci">Pipeline for Application CI</h2> <p>To goal here is to do a Flatpak build for KDE applications whenever they receive a new commit or merge request. We currently have similar CI pipelines running, but they are only for FreeBSD and OpenSuse. I plan to add a third job there, which will build the application inside Flatpak environment, and provide a way to install and test those builds on a local machine.</p> <p>The inspiration for this has been taken from similar pipelines that run on Gnome GitLab. In essence, on every run, we fetch the application's Flatpak manifest, replace its source link with the latest commit and try a build. If the build succeeds, we upload its <code>.flatpakref</code> file as an artefact.</p> <p>My implementation for this is still in an alpha phase and will need some more work to become viable for regular use on KDE applications.</p> <p>The testing repository for this can be found here -&gt; <a href="https://gitlab.com/flyingcakes/kdiff-v2/">https://gitlab.com/flyingcakes/kdiff-v2/</a></p> <h2 id="follow-up-on-checker-data-additions-on-github">Follow up on Checker Data Additions on GitHub</h2> <p>In my last post, I described how I'm adding checker data to manifests hosted on GitHub. I have added the data to <em>most</em> applications. The bigger ones like Krita and KdenLive are still missing data. This should be fixed in due time.</p> <p>We noticed some issues with it, which seems to be related to FEDC itself. It sometimes creates repeated pull requests for the same package.</p> <p>Other issues were caused because I had inadvertently provided wrong links in checker data.</p> <p>None of the issues caused any inconvenience though. The maintainers have been thoroughly verifying pull requests to ensure nothing unexpected goes into the actual application. I fixed those minor issues as and when we got to know about them.</p> <h2 id="links-to-pull-requests">Links to Pull Requests</h2> <h3 id="adding-checker-data">Adding checker data</h3> <ul> <li>Index : <a href="https://github.com/flathub/org.kde.index/pull/3">https://github.com/flathub/org.kde.index/pull/3</a></li> <li>Itinerary : <a href="https://github.com/flathub/org.kde.itinerary/pull/9">https://github.com/flathub/org.kde.itinerary/pull/9</a></li> <li>KAlgebra : <a href="https://github.com/flathub/org.kde.kalgebra/pull/3">https://github.com/flathub/org.kde.kalgebra/pull/3</a></li> <li>KDiamond : <a href="https://github.com/flathub/org.kde.kdiamond/pull/44">https://github.com/flathub/org.kde.kdiamond/pull/44</a></li> <li>KCalc : <a href="https://github.com/flathub/org.kde.kcalc/pull/23">https://github.com/flathub/org.kde.kcalc/pull/23</a></li> <li>KCacheGrind : <a href="https://github.com/flathub/org.kde.kcachegrind/pull/29">https://github.com/flathub/org.kde.kcachegrind/pull/29</a></li> <li>KGeoTag : <a href="https://github.com/flathub/org.kde.kgeotag/pull/2">https://github.com/flathub/org.kde.kgeotag/pull/2</a></li> <li>KFourInLine : <a href="https://github.com/flathub/org.kde.kfourinline/pull/2">https://github.com/flathub/org.kde.kfourinline/pull/2</a></li> <li>KDiff3 : <a href="https://github.com/flathub/org.kde.kdiff3/pull/2">https://github.com/flathub/org.kde.kdiff3/pull/2</a></li> <li>KFind : <a href="https://github.com/flathub/org.kde.kfind/pull/3">https://github.com/flathub/org.kde.kfind/pull/3</a></li> <li>KGeography : <a href="https://github.com/flathub/org.kde.kgeography/pull/44">https://github.com/flathub/org.kde.kgeography/pull/44</a></li> <li>Kid3 : <a href="https://github.com/flathub/org.kde.kid3/pull/3">https://github.com/flathub/org.kde.kid3/pull/3</a></li> <li>Kasts : <a href="https://github.com/flathub/org.kde.kasts/pull/2">https://github.com/flathub/org.kde.kasts/pull/2</a></li> <li>KolorPaint : <a href="https://github.com/flathub/org.kde.kolourpaint/pull/53">https://github.com/flathub/org.kde.kolourpaint/pull/53</a></li> <li>Labplot2 : <a href="https://github.com/flathub/org.kde.labplot2/pull/4">https://github.com/flathub/org.kde.labplot2/pull/4</a></li> <li>KTrip : <a href="https://github.com/flathub/org.kde.ktrip/pull/5">https://github.com/flathub/org.kde.ktrip/pull/5</a></li> <li>Kile : <a href="https://github.com/flathub/org.kde.kile/pull/2">https://github.com/flathub/org.kde.kile/pull/2</a></li> <li>Kongress : <a href="https://github.com/flathub/org.kde.kongress/pull/3">https://github.com/flathub/org.kde.kongress/pull/3</a></li> <li>Kompare : <a href="https://github.com/flathub/org.kde.kompare/pull/1">https://github.com/flathub/org.kde.kompare/pull/1</a></li> <li>Kiten : <a href="https://github.com/flathub/org.kde.kiten/pull/21">https://github.com/flathub/org.kde.kiten/pull/21</a></li> <li>Koko : <a href="https://github.com/flathub/org.kde.koko/pull/4">https://github.com/flathub/org.kde.koko/pull/4</a></li> <li>Konversation : <a href="https://github.com/flathub/org.kde.konversation/pull/23">https://github.com/flathub/org.kde.konversation/pull/23</a></li> <li>KPhotoAlbum : <a href="https://github.com/flathub/org.kde.kphotoalbum/pull/2">https://github.com/flathub/org.kde.kphotoalbum/pull/2</a></li> <li>Konquest : <a href="https://github.com/flathub/org.kde.konquest/pull/22">https://github.com/flathub/org.kde.konquest/pull/22</a></li> <li>Kontrast : <a href="https://github.com/flathub/org.kde.kontrast/pull/18">https://github.com/flathub/org.kde.kontrast/pull/18</a></li> <li>KRDC : <a href="https://github.com/flathub/org.kde.krdc/pull/2">https://github.com/flathub/org.kde.krdc/pull/2</a></li> <li>KRename : <a href="https://github.com/flathub/org.kde.krename/pull/2">https://github.com/flathub/org.kde.krename/pull/2</a></li> <li>KStars : <a href="https://github.com/flathub/org.kde.kstars/pull/1">https://github.com/flathub/org.kde.kstars/pull/1</a></li> <li>KTorrent : <a href="https://github.com/flathub/org.kde.ktorrent/pull/30">https://github.com/flathub/org.kde.ktorrent/pull/30</a></li> <li>KSquares : <a href="https://github.com/flathub/org.kde.ksquares/pull/42">https://github.com/flathub/org.kde.ksquares/pull/42</a></li> <li>KRuler : <a href="https://github.com/flathub/org.kde.kruler/pull/3">https://github.com/flathub/org.kde.kruler/pull/3</a></li> <li>KSudoku : <a href="https://github.com/flathub/org.kde.ksudoku/pull/44">https://github.com/flathub/org.kde.ksudoku/pull/44</a></li> <li>KTuberling : <a href="https://github.com/flathub/org.kde.ktuberling/pull/54">https://github.com/flathub/org.kde.ktuberling/pull/54</a></li> <li>KTurtle : <a href="https://github.com/flathub/org.kde.kturtle/pull/21">https://github.com/flathub/org.kde.kturtle/pull/21</a></li> <li>KUIViewer : <a href="https://github.com/flathub/org.kde.kuiviewer/pull/2">https://github.com/flathub/org.kde.kuiviewer/pull/2</a></li> <li>KWordQuiz : <a href="https://github.com/flathub/org.kde.kwordquiz/pull/43">https://github.com/flathub/org.kde.kwordquiz/pull/43</a></li> <li>Lokalize : <a href="https://github.com/flathub/org.kde.lokalize/pull/29">https://github.com/flathub/org.kde.lokalize/pull/29</a></li> <li>Marble : <a href="https://github.com/flathub/org.kde.marble/pull/22">https://github.com/flathub/org.kde.marble/pull/22</a></li> <li>Massif Visualizer : <a href="https://github.com/flathub/org.kde.massif-visualizer/pull/7">https://github.com/flathub/org.kde.massif-visualizer/pull/7</a></li> <li>Kontact : <a href="https://github.com/flathub/org.kde.kontact/pull/62">https://github.com/flathub/org.kde.kontact/pull/62</a></li> <li>Minuet : <a href="https://github.com/flathub/org.kde.minuet/pull/33">https://github.com/flathub/org.kde.minuet/pull/33</a></li> <li>NeoChat : <a href="https://github.com/flathub/org.kde.neochat/pull/13">https://github.com/flathub/org.kde.neochat/pull/13</a></li> <li>Kubrick : <a href="https://github.com/flathub/org.kde.kubrick/pull/42">https://github.com/flathub/org.kde.kubrick/pull/42</a></li> <li>KTouch : <a href="https://github.com/flathub/org.kde.ktouch/pull/36">https://github.com/flathub/org.kde.ktouch/pull/36</a></li> <li>Nota : <a href="https://github.com/flathub/org.kde.nota/pull/1">https://github.com/flathub/org.kde.nota/pull/1</a></li> <li>Okular : <a href="https://github.com/flathub/org.kde.okular/pull/147">https://github.com/flathub/org.kde.okular/pull/147</a></li> <li>Okteta : <a href="https://github.com/flathub/org.kde.okteta/pull/9">https://github.com/flathub/org.kde.okteta/pull/9</a></li> <li>Pix : <a href="https://github.com/flathub/org.kde.pix/pull/4">https://github.com/flathub/org.kde.pix/pull/4</a></li> <li>Skrooge : <a href="https://github.com/flathub/org.kde.skrooge/pull/23">https://github.com/flathub/org.kde.skrooge/pull/23</a></li> <li>Subtitle Composer : <a href="https://github.com/flathub/org.kde.subtitlecomposer/pull/2">https://github.com/flathub/org.kde.subtitlecomposer/pull/2</a></li> <li>Tellico : <a href="https://github.com/flathub/org.kde.tellico/pull/2">https://github.com/flathub/org.kde.tellico/pull/2</a></li> <li>Palapeli : <a href="https://github.com/flathub/org.kde.palapeli/pull/45">https://github.com/flathub/org.kde.palapeli/pull/45</a></li> <li>KLettres : <a href="https://github.com/flathub/org.kde.klettres/pull/20">https://github.com/flathub/org.kde.klettres/pull/20</a></li> <li>KNetWalk : <a href="https://github.com/flathub/org.kde.knetwalk/pull/43">https://github.com/flathub/org.kde.knetwalk/pull/43</a></li> <li>KNavalBattle : <a href="https://github.com/flathub/org.kde.knavalbattle/pull/42">https://github.com/flathub/org.kde.knavalbattle/pull/42</a></li> <li>KLines : <a href="https://github.com/flathub/org.kde.klines/pull/42">https://github.com/flathub/org.kde.klines/pull/42</a></li> <li>Klickety : <a href="https://github.com/flathub/org.kde.klickety/pull/43">https://github.com/flathub/org.kde.klickety/pull/43</a></li> <li>KJumpingCube : <a href="https://github.com/flathub/org.kde.kjumpingcube/pull/44">https://github.com/flathub/org.kde.kjumpingcube/pull/44</a></li> <li>KillBots : <a href="https://github.com/flathub/org.kde.killbots/pull/42">https://github.com/flathub/org.kde.killbots/pull/42</a></li> <li>Kigo : <a href="https://github.com/flathub/org.kde.kigo/pull/41">https://github.com/flathub/org.kde.kigo/pull/41</a></li> <li>Kig : <a href="https://github.com/flathub/org.kde.kig/pull/21">https://github.com/flathub/org.kde.kig/pull/21</a></li> <li>KGoldRunner : <a href="https://github.com/flathub/org.kde.kgoldrunner/pull/41">https://github.com/flathub/org.kde.kgoldrunner/pull/41</a></li> <li>KGet : <a href="https://github.com/flathub/org.kde.kget/pull/4">https://github.com/flathub/org.kde.kget/pull/4</a></li> <li>Tokodon : <a href="https://github.com/flathub/org.kde.tokodon/pull/1">https://github.com/flathub/org.kde.tokodon/pull/1</a></li> <li>Vvave : <a href="https://github.com/flathub/org.kde.vvave/pull/2">https://github.com/flathub/org.kde.vvave/pull/2</a></li> </ul> <h3 id="other-minor-fixes">Other minor fixes</h3> <ul> <li>Nota - Fix for filename without extension : <a href="https://github.com/flathub/org.kde.nota/pull/3">https://github.com/flathub/org.kde.nota/pull/3</a></li> <li>Pix - Add filename for applet window button : <a href="https://github.com/flathub/org.kde.pix/pull/15">https://github.com/flathub/org.kde.pix/pull/15</a></li> <li>Labplot2 - Remove checker data for labplot and cfitsio : <a href="https://github.com/flathub/org.kde.labplot2/pull/12">https://github.com/flathub/org.kde.labplot2/pull/12</a></li> <li>Itinerary - Fix link for poppler : <a href="https://github.com/flathub/org.kde.itinerary/pull/11">https://github.com/flathub/org.kde.itinerary/pull/11</a></li> <li>Koko - Fix exiv2 checker data : <a href="https://github.com/flathub/org.kde.koko/pull/6">https://github.com/flathub/org.kde.koko/pull/6</a></li> </ul> Debut Snehit Sah [email protected] http://snehit.dev 2022-03-15T00:00:00+00:00 2022-03-15T00:00:00+00:00 https://snehit.dev/posts/french/debut/ <p>Bonjour !</p> <p>Ceci est mon premier poteau de blog en français. Je suis un étudiant en ingénierie. J'aime étudier la science informatique.</p> <p>J'apprends le francais. J'ai étudié le français à l'école pendant trois ans. Mais j'ai oublié. Donc je vais l'étudier à nouveau.</p> <span id="continue-reading"></span> <p>Au revoir !</p> Status update: FEDC and Update Automation - post #4 Snehit Sah [email protected] http://snehit.dev 2022-03-10T00:00:00+00:00 2022-03-10T00:00:00+00:00 https://snehit.dev/posts/kde/sok-2022/fedc-and-update-automation/ <p>Hello!</p> <p>This is my fourth status update for Season of KDE 2022.</p> <p>In my <a href="https://snehit.dev/posts/kde/sok-2022/completing-a-milestone/">last post</a> I told how packaging was almost done and I was looking out to automate updates.</p> <span id="continue-reading"></span><h2 id="finalizing-the-checker-data">Finalizing the checker data</h2> <p>There are multiple backends that can be used with Flatpak External Data Checker. I initially planned to use the HTML checker, for it seemed logical at that time. But by the time I finalized it, I was already gravitating towards Anitya Release Monitoring. Since Anitya already has version tracking for most packages, it seemed a bit easier than the HTML checker. With Anitya, all I need to know is the project id, which is just a simple search on their website.</p> <p>The packages that don't exist on Anitya are quite easy to submit. A Fedora account is all it takes. (you can use any Open ID). For example, I added <a href="https://release-monitoring.org/project/242801/">Falkon</a> on Anitya.</p> <h3 id="roadblocks">Roadblocks</h3> <p>There are certain corner cases where FEDC didn't work as expected. GPGME is the first example. The download server for GPGME is incorrectly setting Content-Encoding as <code>text/*</code>, which FEDC discards, as it <em>could</em> be an error page. The right way out will be to get GPGME developers in the loop and inform them of this issue.</p> <p>Another package, SQLite, uses the current year in its URL, making it difficult to predict via a script.</p> <h2 id="experimenting-with-github-actions">Experimenting with GitHub Actions</h2> <p>I made a <a href="https://github.com/flyingcakes85/kontact-fedc/">test repository</a> to demonstrate the working of FEDC via a GitHub action. We were planning to get an access token added to KDE repos on Flathub GitHub organization so that we could utilize our GitHub Action. One of my submissions had erroneous checker data. It went unnoticed, until the Flathub bot made an unexpected pull request on a repo. That made us realise that we don't actually need to add an access token. Flathub runs the updater and makes pull requests automatically.</p> <p>Happy accident!</p> <p>So, all I am required to do is to add checker data to as many manifests as possible. The update for 21.12.3 was done manually, but the updates next month should be mostly automated!</p> <p>Links to all my pull requests are at end of this post.</p> <h2 id="next-steps">Next steps</h2> <p>I plan to add checker data to all the remaining applications (~80) in the next 2-to 3 days. I'm also parallelly looking over to use FEDC on KDE Invent to automatically update non KDE dependencies on master manifest repo.</p> <h2 id="links-to-pull-requests">Links to pull requests</h2> <h3 id="adding-checker-data">Adding checker data</h3> <ul> <li>Akregator : <a href="https://github.com/flathub/org.kde.akregator/pull/5">https://github.com/flathub/org.kde.akregator/pull/5</a></li> <li>Artikulate : <a href="https://github.com/flathub/org.kde.artikulate/pull/9">https://github.com/flathub/org.kde.artikulate/pull/9</a></li> <li>Blinken : <a href="https://github.com/flathub/org.kde.blinken/pull/22">https://github.com/flathub/org.kde.blinken/pull/22</a></li> <li>Bomber : <a href="https://github.com/flathub/org.kde.bomber/pull/17">https://github.com/flathub/org.kde.bomber/pull/17</a></li> <li>Bovo : <a href="https://github.com/flathub/org.kde.bovo/pull/18">https://github.com/flathub/org.kde.bovo/pull/18</a></li> <li>Falkon : <a href="https://github.com/flathub/org.kde.falkon/pull/3">https://github.com/flathub/org.kde.falkon/pull/3</a></li> <li>Granatier : <a href="https://github.com/flathub/org.kde.granatier/pull/16">https://github.com/flathub/org.kde.granatier/pull/16</a></li> <li>Filelight : <a href="https://github.com/flathub/org.kde.filelight/pull/2">https://github.com/flathub/org.kde.filelight/pull/2</a></li> <li>KColorChooser : <a href="https://github.com/flathub/org.kde.kcolorchooser/pull/3">https://github.com/flathub/org.kde.kcolorchooser/pull/3</a></li> <li>Kalzium : <a href="https://github.com/flathub/org.kde.kalzium/pull/44">https://github.com/flathub/org.kde.kalzium/pull/44</a></li> <li>Kamoso : <a href="https://github.com/flathub/org.kde.kamoso/pull/5">https://github.com/flathub/org.kde.kamoso/pull/5</a></li> <li>Kanagram : <a href="https://github.com/flathub/org.kde.kanagram/pull/21">https://github.com/flathub/org.kde.kanagram/pull/21</a></li> <li>Kapman : <a href="https://github.com/flathub/org.kde.kapman/pull/42">https://github.com/flathub/org.kde.kapman/pull/42</a></li> <li>KAtomic : <a href="https://github.com/flathub/org.kde.katomic/pull/41">https://github.com/flathub/org.kde.katomic/pull/41</a></li> <li>KBlackbox : <a href="https://github.com/flathub/org.kde.kblackbox/pull/17">https://github.com/flathub/org.kde.kblackbox/pull/17</a></li> <li>KBlocks : <a href="https://github.com/flathub/org.kde.kblocks/pull/42">https://github.com/flathub/org.kde.kblocks/pull/42</a></li> <li>KBounce : <a href="https://github.com/flathub/org.kde.kbounce/pull/43">https://github.com/flathub/org.kde.kbounce/pull/43</a></li> <li>KBreakout : <a href="https://github.com/flathub/org.kde.kbreakout/pull/2">https://github.com/flathub/org.kde.kbreakout/pull/2</a></li> <li>KBruch : <a href="https://github.com/flathub/org.kde.kbruch/pull/40">https://github.com/flathub/org.kde.kbruch/pull/40</a></li> <li>KDF : <a href="https://github.com/flathub/org.kde.kdf/pull/2">https://github.com/flathub/org.kde.kdf/pull/2</a></li> </ul> <h3 id="updates-for-21-12-3">Updates for 21.12.3</h3> <ul> <li>KGeoTag : <a href="https://github.com/flathub/org.kde.kgeotag/pull/1">https://github.com/flathub/org.kde.kgeotag/pull/1</a></li> <li>Akregator : <a href="https://github.com/flathub/org.kde.akregator/pull/4">https://github.com/flathub/org.kde.akregator/pull/4</a></li> <li>KRuler : <a href="https://github.com/flathub/org.kde.kruler/pull/2">https://github.com/flathub/org.kde.kruler/pull/2</a></li> <li>KFind : <a href="https://github.com/flathub/org.kde.kfind/pull/2">https://github.com/flathub/org.kde.kfind/pull/2</a></li> <li>KDevelop : <a href="https://github.com/flathub/org.kde.kdevelop/pull/16">https://github.com/flathub/org.kde.kdevelop/pull/16</a></li> <li>KUIViewer : <a href="https://github.com/flathub/org.kde.kuiviewer/pull/1">https://github.com/flathub/org.kde.kuiviewer/pull/1</a></li> <li>KRDC : <a href="https://github.com/flathub/org.kde.krdc/pull/1">https://github.com/flathub/org.kde.krdc/pull/1</a></li> <li>KColorChooser : <a href="https://github.com/flathub/org.kde.kcolorchooser/pull/2">https://github.com/flathub/org.kde.kcolorchooser/pull/2</a></li> <li>KGet : <a href="https://github.com/flathub/org.kde.kget/pull/3">https://github.com/flathub/org.kde.kget/pull/3</a></li> <li>KDF : <a href="https://github.com/flathub/org.kde.kdf/pull/1">https://github.com/flathub/org.kde.kdf/pull/1</a></li> <li>Koko : <a href="https://github.com/flathub/org.kde.koko/pull/3">https://github.com/flathub/org.kde.koko/pull/3</a></li> <li>GwenView : <a href="https://github.com/flathub/org.kde.gwenview/pull/24">https://github.com/flathub/org.kde.gwenview/pull/24</a></li> <li>Kdenline : <a href="https://github.com/flathub/org.kde.kdenlive/pull/168">https://github.com/flathub/org.kde.kdenlive/pull/168</a></li> <li>Okular : <a href="https://github.com/flathub/org.kde.okular/pull/144">https://github.com/flathub/org.kde.okular/pull/144</a></li> <li>Itineary : <a href="https://github.com/flathub/org.kde.itinerary/pull/8">https://github.com/flathub/org.kde.itinerary/pull/8</a></li> <li>KTorrent : <a href="https://github.com/flathub/org.kde.ktorrent/pull/29">https://github.com/flathub/org.kde.ktorrent/pull/29</a></li> <li>KTuberling : <a href="https://github.com/flathub/org.kde.ktuberling/pull/53">https://github.com/flathub/org.kde.ktuberling/pull/53</a></li> <li>Konversation : <a href="https://github.com/flathub/org.kde.konversation/pull/22">https://github.com/flathub/org.kde.konversation/pull/22</a></li> <li>Kontact : <a href="https://github.com/flathub/org.kde.kontact/pull/61">https://github.com/flathub/org.kde.kontact/pull/61</a></li> <li>KCalc : <a href="https://github.com/flathub/org.kde.kcalc/pull/22">https://github.com/flathub/org.kde.kcalc/pull/22</a></li> <li>Ark : <a href="https://github.com/flathub/org.kde.ark/pull/38">https://github.com/flathub/org.kde.ark/pull/38</a></li> <li>Kontrast : <a href="https://github.com/flathub/org.kde.kontrast/pull/17">https://github.com/flathub/org.kde.kontrast/pull/17</a></li> <li>Kamoso : <a href="https://github.com/flathub/org.kde.kamoso/pull/4">https://github.com/flathub/org.kde.kamoso/pull/4</a></li> <li>Elisa : <a href="https://github.com/flathub/org.kde.elisa/pull/57">https://github.com/flathub/org.kde.elisa/pull/57</a></li> <li>Dolphin : <a href="https://github.com/flathub/org.kde.dolphin/pull/72">https://github.com/flathub/org.kde.dolphin/pull/72</a></li> <li>Filelight : <a href="https://github.com/flathub/org.kde.filelight/pull/1">https://github.com/flathub/org.kde.filelight/pull/1</a></li> </ul> <p>I will see you in next post with more updates!</p> Status update: Completing a milestone - post #3 Snehit Sah [email protected] http://snehit.dev 2022-02-26T00:00:00+00:00 2022-02-26T00:00:00+00:00 https://snehit.dev/posts/kde/sok-2022/completing-a-milestone/ <p>Hey!</p> <p>This is my third post for SoK 2022. Let's go through what I've done since my last post, and what I plan to do next.</p> <h2 id="packaging">Packaging</h2> <p>I had already submitted a good number of packages to Flathub early on, because I had time, and didn't want my schedule to become too packed all of a sudden later on.</p> <span id="continue-reading"></span> <p>One month into Season of KDE, and almost every high priority and medium priority packages have been submitted. Most have been accepted to Flathub, while some are awaiting review. I'll list down the submissions accepted after my last post.</p> <h3 id="new-packages-on-flathub">New packages on Flathub</h3> <ol> <li>Ikona <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.Ikona">https://flathub.org/apps/details/org.kde.Ikona</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.Ikona">https://github.com/flathub/org.kde.Ikona</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2829">https://github.com/flathub/flathub/pull/2829</a></li> </ul> </li> <li>KUIViewer <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.kuiviewera">https://flathub.org/apps/details/org.kde.kuiviewer</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.kuiviewer">https://github.com/flathub/org.kde.kuiviewer</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2838">https://github.com/flathub/flathub/pull/2838</a></li> </ul> </li> <li>KRDC <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.krdc">https://flathub.org/apps/details/org.kde.krdc</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.krdc">https://github.com/flathub/org.kde.krdc</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2859">https://github.com/flathub/flathub/pull/2859</a></li> </ul> </li> </ol> <h3 id="updates-to-existing-packages">Updates to existing packages</h3> <ol> <li>Update Akregator to 21.12.2 : <a href="https://github.com/flathub/org.kde.akregator/pull/1">https://github.com/flathub/org.kde.akregator/pull/1</a></li> <li>Minor updates to KRename : <a href="https://github.com/flathub/org.kde.krename/pull/1">https://github.com/flathub/org.kde.krename/pull/1</a></li> </ol> <h3 id="upstream-appdata-patches">Upstream appdata patches</h3> <ol> <li>Skanlite : <a href="https://invent.kde.org/graphics/skanlite/-/merge_requests/29">https://invent.kde.org/graphics/skanlite/-/merge_requests/29</a></li> <li>Heaptrack : <a href="https://invent.kde.org/sdk/heaptrack/-/merge_requests/10">https://invent.kde.org/sdk/heaptrack/-/merge_requests/10</a></li> <li>KWave : <a href="https://invent.kde.org/multimedia/kwave/-/merge_requests/8">https://invent.kde.org/multimedia/kwave/-/merge_requests/8</a></li> <li>Ikona : <a href="https://invent.kde.org/sdk/ikona/-/merge_requests/8">https://invent.kde.org/sdk/ikona/-/merge_requests/8</a></li> </ol> <h2 id="pending-submissions">Pending submissions</h2> <p>There are 5 packages currently under review.</p> <ul> <li><strong>Skanlite</strong> seems to be in limbo for now, since I don't have a scanner to test it. Arranging for one is possible, but it won't be a long term solution if I am to maintain the package.</li> <li><strong>Zanshin</strong> has issues with the migrator, which blocks starting the application. I've put it on the back-burner for the time being.</li> <li><strong>Nota</strong> is mostly done. It uses a custom implementation for file picker, which means it can not use portal. We could have it as a beta package for now. I might look into patching the source code to use Qt file picker so that Nota can utilize portals. This again is a task for later.</li> <li><strong>Kwave</strong> needs a minor fix to make one of its dependencies play well with <code>aarch64</code>. Otherwise, it is done.</li> <li><strong>Heaptrack</strong> needs to be updated with extra permissions. I'll get this done soon.</li> </ul> <h2 id="rest-of-the-packages">Rest of the packages</h2> <ul> <li><strong>Kile</strong> isn't detecting Texlive during runtime, which has become a mystery movie now. I'm hopeful to fix it pretty soon.</li> <li><strong>KAlarm</strong> relies on KAuth for certain features, which cannot be run inside Flatpak environment. While I could come up with the relevant patches to CMake files, so as to not build KAuth, the application itself needs some patching to disable those features when running inside Flatpak environment.</li> <li><strong>K3b</strong> has the same issues as KAlarm. Again, I have made the patches for build, but I'm yet to patch the source code to disable those features.</li> </ul> <p>I plan to work on KAlarm and K3b source code during the second week of March if we decide to make them a priority.</p> <p>With majority of the packaging work done, I should thank all the reviewers who vetted my submissions to Flathub, especially <a href="https://github.com/hfiguiere">Hubert Figuière</a> who has been helpful and patient even when I seem to do stupid mistakes :)</p> <h2 id="plans-for-the-next-milestone">Plans for the next milestone</h2> <p>As I mentioned at the beginning, packaging work is almost sorted out, barring a couple of apps here and there. This leaves me with about a month and a half to work on other things I planned to.</p> <p>I am playing around with <a href="https://github.com/flathub/flatpak-external-data-checker">Flatpak External Data Checker</a>, which can bring about some automation in the update process.</p> <p>I'm still in the "exploration phase" for this tool. While there are multiple ways I could use it for KDE Flatpak manifests, I want to take up the one that best suits the release process KDE has.</p> <p>Taking my leave for this post. I hope to publish more updates and improvements in my next one!</p> Status update: Mass packaging, and mass learning - post #2 Snehit Sah [email protected] http://snehit.dev 2022-02-06T00:00:00+00:00 2022-02-06T00:00:00+00:00 https://snehit.dev/posts/kde/sok-2022/mass-packaging-mass-learning/ <p>Hey!</p> <p>This is my second post for SoK 2022. Its going to be lot more technical than my last one. Lets dive into all that we did in past few days.</p> <span id="continue-reading"></span><h2 id="learning-packaging">Learning packaging</h2> <p>As I had mentioned in my <a href="https://snehit.dev/posts/kde/sok-2022/beginning-with-sok-2022/">last post</a>, I already knew the basics of packaging. Flatpak is certainly new for me though. I have used Flatpaks, but never published them.</p> <p>It was easy to learn packaging and writing manifests. I submitted a couple of easy applications to Flathub before the contribution period started, so as to get a good idea of what I'll be doing during the coming weeks.</p> <h2 id="challenges-faced">Challenges faced</h2> <h3 id="incomplete-appdata-info">Incomplete Appdata info</h3> <p>Many upstream packages did not have a complete appdata.xml file. Most noticeably, the <a href="https://hughsie.github.io/oars/">OARS</a> data was missing. However, I did not get to know about it until I submitted my first package, and <a href="https://github.com/flathub/flathub/pull/2748#issuecomment-1008280898">it failed CI test</a>.</p> <p>Logs made it clear the appdata was at fault. Poking around, I fixed the appdata, but I needed a quick way to verify appdata for future packages. I made an alias in my shell, which would do the job for me.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">ad</span><span>=&quot;</span><span style="color:#a3be8c;">flatpak run --env=G_DEBUG=fatal-criticals org.freedesktop.appstream-glib validate </span><span style="color:#96b5b4;">\$</span><span style="color:#a3be8c;">(find . -name </span><span style="color:#96b5b4;">\&quot;</span><span style="color:#a3be8c;">*appdata.xml</span><span style="color:#96b5b4;">\&quot;</span><span style="color:#a3be8c;">)</span><span>&quot; </span></code></pre> <p>You need to first <code>cd</code> into your build directory. And then simply run <code>ad</code>. It will find all appdata files, and validate them.</p> <h3 id="using-right-sources">Using right sources</h3> <p>My first three submissions used a git source rather than release tarballs. While using a git source doesn't pose major issues, release tarballs are easier to work with.</p> <h3 id="using-right-permissions">Using right permissions</h3> <p>Back when I started, I did not know which permissions I had to use for different packages. All it required was to read the <a href="https://docs.flatpak.org/en/latest/sandbox-permissions.html">documentation on Flatpak website</a>. Running an app with missing permissions usually printed errors in the console, which could be used to verify permissions. Nearly every GUI application requires <code>--socket=fallback-x11</code>, <code>--socket=ipc</code>, <code>--socket=wayland</code>, and for applications using OpenGL, <code>--device=dri</code>. If application required network access, add <code>--share=network</code>.</p> <p>For filesystem access, you can use <code>--filesystem=host</code>, but most of the times, you don't need such a broad permission. You have options like <code>--filesystem=home</code>, <code>--filesystem=/path/to/dir</code> and <code>--filesystem=xdg-name</code>, where <code>name</code> is one of the XDG directories. These can be used to limit filesystem access, and be more closer to the idea of sandboxing applications.</p> <h3 id="other-minor-issues">Other minor issues</h3> <p>There were a couple of other minor issues with my initial few manifests. Reviewers suggested changes, and I gradually understood them and avoided them.</p> <h2 id="portal-exists">Portal exists</h2> <p>So, I had zero idea about Portals, which allow a Flatpak application to access files on the user filesystem, without requiring explicit permissions in manifest. I only got to know about it during reviews.</p> <h2 id="submissions-list">Submissions list</h2> <p>I'm listing only the accepted submissions here.</p> <h3 id="submissions-to-flathub">Submissions to Flathub</h3> <ol> <li>KFind <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.kfind">https://flathub.org/apps/details/org.kde.kfind</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.kfind">https://github.com/flathub/org.kde.kfind</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2748">https://github.com/flathub/flathub/pull/2748</a></li> </ul> </li> <li>KRuler <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.kruler">https://flathub.org/apps/details/org.kde.kruler</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.kruler">https://github.com/flathub/org.kde.kruler</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2750">https://github.com/flathub/flathub/pull/2750</a></li> </ul> </li> <li>Cantor <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.cantor">https://flathub.org/apps/details/org.kde.cantor</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.cantor">https://github.com/flathub/org.kde.cantor</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2762">https://github.com/flathub/flathub/pull/2762</a></li> </ul> </li> <li>KDiff3 <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.kdiff3">https://flathub.org/apps/details/org.kde.kdiff3</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.kdiff3">https://github.com/flathub/org.kde.kdiff3</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2764">https://github.com/flathub/flathub/pull/2764</a></li> </ul> </li> <li>KColorChooser <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.kcolorchooser">https://flathub.org/apps/details/org.kde.kcolorchooser</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.kcolorchooser">https://github.com/flathub/org.kde.kcolorchooser</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2766">https://github.com/flathub/flathub/pull/2766</a></li> </ul> </li> <li>KAlgebra <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.kalgebra">https://flathub.org/apps/details/org.kde.kalgebra</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.kalgebra">https://github.com/flathub/org.kde.kalgebra</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2771">https://github.com/flathub/flathub/pull/2771</a></li> </ul> </li> <li>KPhotoAlbum <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.kphotoalbum">https://flathub.org/apps/details/org.kde.kphotoalbum</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.kphotoalbum">https://github.com/flathub/org.kde.kphotoalbum</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2775">https://github.com/flathub/flathub/pull/2775</a></li> </ul> </li> <li>Falkon <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.falkon">https://flathub.org/apps/details/org.kde.falkon</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.falkon">https://github.com/flathub/org.kde.falkon</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2781">https://github.com/flathub/flathub/pull/2781</a></li> </ul> </li> <li>KGeoTag <ul> <li>Flathub listing : <a href="https://flathub.org/apps/details/org.kde.kgeotag">https://flathub.org/apps/details/org.kde.kgeotag</a></li> <li>Repo : <a href="https://github.com/flathub/org.kde.kgeotag">https://github.com/flathub/org.kde.kgeotag</a></li> <li>Pull request : <a href="https://github.com/flathub/flathub/pull/2814">https://github.com/flathub/flathub/pull/2814</a></li> </ul> </li> </ol> <h3 id="upstream-code-patches">Upstream code patches</h3> <p>Thanks to help from Albert Cid, I was able to push some minor updates to KDF.</p> <p>KDF has option to open disk with a custom command from the user. By default, this opens disk in Dolphin file manager. However, this fails when Dolphin is not installed on system. The issue arose when packaging KDF for Flathub required including Dolphin in the manifest, which was not ideal. As a result, KDF was put on hold, and I was suggested to add a feature that would open drives in system default file manager. Thanks to Aleix Pol, I already had an idea about the changes to make in source code. My first pull request was closed because I removed the feature for using custom file manager command.</p> <p>In my second pull request, I added the feature to open disk in system default file manager, and retained the option to specify a custom file manager command. User can easily switch them in settings. Albert suggested I send a patch to disable option to specify custom command, as they aren't supported in Flatpak environment.</p> <ul> <li>Pull request adding feature to open drive in default file manager : <a href="https://invent.kde.org/utilities/kdf/-/merge_requests/5">https://invent.kde.org/utilities/kdf/-/merge_requests/5</a></li> <li>Pull request disabling file manager command option in Flatpak environment : <a href="https://invent.kde.org/utilities/kdf/-/merge_requests/7">https://invent.kde.org/utilities/kdf/-/merge_requests/7</a></li> <li>Minor patch to update condition check to be more idiomatic : <a href="https://invent.kde.org/utilities/kdf/-/merge_requests/6">https://invent.kde.org/utilities/kdf/-/merge_requests/6</a></li> </ul> <h3 id="updates-pushed">Updates pushed</h3> <ol> <li>Falkon update to 3.2 : <a href="https://github.com/flathub/org.kde.falkon/pull/2">https://github.com/flathub/org.kde.falkon/pull/2</a></li> <li>Exiv2 update for Koko : <a href="https://github.com/flathub/org.kde.koko/pull/2">https://github.com/flathub/org.kde.koko/pull/2</a></li> <li>Exiv2 update for Kdenlive : <a href="https://github.com/flathub/org.kde.kdenlive/pull/165">https://github.com/flathub/org.kde.kdenlive/pull/165</a></li> <li>Exiv2 update for Krita : <a href="https://github.com/flathub/org.kde.krita/pull/51">https://github.com/flathub/org.kde.krita/pull/51</a></li> <li>Exiv2 update for GwenView : <a href="https://github.com/flathub/org.kde.gwenview/pull/22">https://github.com/flathub/org.kde.gwenview/pull/22</a></li> <li>Exiv2 update for KPhotoAlbum : <a href="https://github.com/flathub/org.kde.kphotoalbum/pull/1">https://github.com/flathub/org.kde.kphotoalbum/pull/1</a></li> <li>Exiv2 update to Flatpak master repo : <a href="https://invent.kde.org/packaging/flatpak-kde-applications/-/merge_requests/74">https://invent.kde.org/packaging/flatpak-kde-applications/-/merge_requests/74</a></li> <li>Eigen update to Flatpak master repo: <a href="https://invent.kde.org/packaging/flatpak-kde-applications/-/merge_requests/72">https://invent.kde.org/packaging/flatpak-kde-applications/-/merge_requests/72</a></li> <li>Boost update to Flatpak master repo : <a href="https://invent.kde.org/packaging/flatpak-kde-applications/-/merge_requests/71">https://invent.kde.org/packaging/flatpak-kde-applications/-/merge_requests/71 </a></li> </ol> <h3 id="upstream-appdata-patches">Upstream appdata patches</h3> <ol> <li>KFloppy : <a href="https://invent.kde.org/utilities/kfloppy/-/merge_requests/1">https://invent.kde.org/utilities/kfloppy/-/merge_requests/1</a></li> <li>KRuler : <a href="https://invent.kde.org/graphics/kruler/-/merge_requests/5">https://invent.kde.org/graphics/kruler/-/merge_requests/5</a></li> <li>Cantor : <a href="https://invent.kde.org/education/cantor/-/merge_requests/37">https://invent.kde.org/education/cantor/-/merge_requests/37</a></li> <li>KFind : <a href="https://invent.kde.org/utilities/kfind/-/merge_requests/8">https://invent.kde.org/utilities/kfind/-/merge_requests/8</a></li> <li>KDiff3 : <a href="https://invent.kde.org/sdk/kdiff3/-/merge_requests/37">https://invent.kde.org/sdk/kdiff3/-/merge_requests/37</a></li> <li>KAlgebra : <a href="https://invent.kde.org/education/kalgebra/-/merge_requests/22">https://invent.kde.org/education/kalgebra/-/merge_requests/22</a></li> <li>Akregator : <a href="https://invent.kde.org/pim/akregator/-/merge_requests/22">https://invent.kde.org/pim/akregator/-/merge_requests/22</a></li> <li>KPhotoAlbum : <a href="https://invent.kde.org/graphics/kphotoalbum/-/merge_requests/18">https://invent.kde.org/graphics/kphotoalbum/-/merge_requests/18</a></li> <li>KGeoTag : <a href="https://invent.kde.org/graphics/kgeotag/-/merge_requests/13">https://invent.kde.org/graphics/kgeotag/-/merge_requests/13</a></li> <li>KDF : <a href="https://invent.kde.org/utilities/kdf/-/merge_requests/3">https://invent.kde.org/utilities/kdf/-/merge_requests/3</a></li> <li>Dolphin : <a href="https://invent.kde.org/system/dolphin/-/merge_requests/325">https://invent.kde.org/system/dolphin/-/merge_requests/325</a></li> <li>Falkon : <a href="https://invent.kde.org/network/falkon/-/merge_requests/27">https://invent.kde.org/network/falkon/-/merge_requests/27</a></li> </ol> <p>Thanks to the KDE team for being patient with reviews and helping me in the roadblocks I faced!</p> So... How do you get started with open source contributions? Snehit Sah [email protected] http://snehit.dev 2022-02-03T00:00:00+00:00 2022-02-03T00:00:00+00:00 https://snehit.dev/posts/foss/starting-with-open-source/ <blockquote> <p>DISCLAIMER : This post is entirely my personal view, and does not reflect that of any projects I contribute(d) to.</p> </blockquote> <p>Hey! In this post I've shared my personal experience with contributing to open source projects. I'm still a learner, and probably will be one for rest of my life. But I believe I'm beyond that point where I was confused about "how do I even start". I'm recording my experience in hope that it proves to be useful to someone else.</p> <span id="continue-reading"></span> <p>Since this post is meant to record my personal experience and observations, I have glossed over some commonly known practices like looking for <code>good first issues</code>, or learning basics of the toolchain you'll be using. I find those advice to be abundantly available on the internet.</p> <h2 id="be-inspired">Be inspired</h2> <p>The first step is pretty simple. <strong>Be inspired!</strong></p> <p>As simple as it sounds, many people don't know exactly <em>why</em> they should be contributing to open source projects.</p> <p>Do you want to improve application reliability for thousands (or even millions) of users around the world? Do you think you can add a cool feature to your favorite application? Do you believe that you can lend a helping hand to the developers pushing updates to applications you use daily? (and many of them are probably doing it without any pay)</p> <p>If your answer to any of the above is "yes", you've already completed the most difficult step.</p> <h3 id="finding-true-love">Finding true love</h3> <p>If your answer was "no", well, how do you find that application or organization where you're truly motivated to contribute? First step wolud be start using more open source software. As you increase your exposure with open source software, you'll eventually find a software that you really want to help with and improve upon.</p> <p>I <em>really</em> suggest switching to a Linux distribution at this point, because that will make your life much easier.</p> <p>My story, you ask? I have tried contributing to open source projects here and there, but the lack of real motivation was a big friction point for me. Fast-forward to April 2020, when I first used Endeavour OS. I found it to be a great distribution, offering the experience I really liked and believed in. Months later, I realized I really wanted to help them out. In whatever small way I can. February 2022 marks one year of me being on the team.</p> <p>If you try contributing to a software you use, it will be much easier for you to test changes and come up with new ideas/ improvements.</p> <h2 id="but-i-don-t-know-coding">But, I don't know coding :(</h2> <blockquote> <p>"I don't know coding, how do I contribute?"</p> </blockquote> <p>This is a <em>big</em> misconception among people new to the open source scene. Programming is just one part of the process. There are many other things a project needs help with. Graphics, translation, cloud infrastructure maintenance, promotions, testing, support... KDE even had openings for music producers willing to work on <a href="https://community.kde.org/SoK/Ideas/2022#Plasma_Sound_Design">sound design for Plasma</a>!</p> <p>Some of these don't even require a very high technical IQ. Take for example testing - an average Joe is as suited to test applications as the project developer, since most of the users are going to be the average Joe.</p> <p>On Endeavour OS, I do testing, theming, packaging etc. Any one who can write code to traverse an array can certainly do these things. So you can already guess there is no coding involved. But my favorite work is seeing those experienced people discuss problems and find solutions. That is what grows me as a learner.</p> <h2 id="however-that-doesn-t-get-me-into-xyz-open-source-event">However, that doesn't get me into XYZ open source event</h2> <blockquote> <p>"Most open source events for students are geared towards programming, so how do I make it if I contribute with other stuff you just mentioned above?"</p> </blockquote> <p>If you've reached here, I suppose you said "yes" to the questions I put up in the first section. If you're doing this <strong>only</strong> to get into an open source event - that would <em>totally</em> defeat the purpose. Yes, it's good to try getting into these, but in case you're not able to make it, you shouldn't stop contributing to open source altogether. You can <em>still</em> contribute even if you're not a part of any student event. What should motivate you is the fact that you'll be improving user experience for thousands (or millions) around the world.</p> <p>Even if you don't contribute code, there is a <em>lot</em> to learn. Just by seeing how the project members function, you get an idea about managing large communities. You get better with your communication skills. You learn more about the organization and make friends, who could certainly help or guide you. (seriously, knowing an experienced person is way better than a hundred unknown LinkedIn connections)</p> <h2 id="ok-so-how-do-i-start">Ok so, how do I start?</h2> <p>You've finally found the project(s) you want to work on. What do you do now?</p> <p>First up, join whatever communication platform the project uses. Matrix, IRC, forum and mailing lists are the common ones. Introduce yourself - keep it short and to the point. List your technical skills <em>that are relevant to the project</em>. You don't go to a kernel development group and say that you know React. (unless you're discussing their website) Most likely, you're going to be ignored. It shows that you did not try to read up what the project is about and how they do their work. Introducing yourself is - undoubtedly - one of the most dreaded questions. Looking back, I find that my non-coding days at Endeavour OS taught me a lot about how open source projects function. Being a mini maintainer myself, I have seen quite a few potential contributors. I know <em>what</em> a project maintainer would like to hear. And that helps me when I am the one introducing myself in communities where I'm new. From the last section - even if you're not programming for a project, you're still progressing faster than you know.</p> <p>Stalking communication channels, I've seen a couple of copy-paste introductions and project ideas. The posters had put in absolutely zero effort in even looking up what kind of products does organization makes. As a result, they either were gracefully ignored, or received a feeble response. So, do little bit of research beforehand. Do your ideas suit the project goals and philosophy? It is much easier and smoother working on a project where you believe in the goals and philosophy.</p> <p>Once you have introduced yourself, a community member should point you towards the resources and relevant communication channels where you could help out. Do note, exactly <a href="https://en.wikipedia.org/wiki/Nobody_(username)"><code>nobody</code></a> will spoon-feed you. Most likely, you'll get link to a wiki page, or link to a different group. It's your task to explore and follow the links to find what you want to help with.</p> <p>Say, you want to join the promo team. Of course, you'll first need to join their channel. For a couple of days, try to just observe how they work. They are probably more efficient than the way you're used to working with your friends. Try to understand the tone and air of the channel. (you never want to crack an out-of-place joke) Once you feel you understand their flow, start chipping in with your suggestions, ideas and opinions. Again, you're probably not contributing something tangible at the beginning, but one idea leads to another - you never know when your simple idea transforms into a lengthy discussion and ends up as the next big thing.</p> <p><em>And obviously, never send memes in #general XD</em></p> <h2 id="if-you-actually-want-to-get-into-coding">If you actually want to get into coding...</h2> <p>It is a tough ride ahead, but I promise, it is <em>very</em> rewarding. As I said earlier, if you are contributing to a software you already use, chances are you already have some suggestions or ideas to make it better. Why not take them as the starting point? Before starting to work on anything, it is always good to discuss with other team members about the changes. It is possible that your suggestion goes against the project philosophy, so it might need some tweaking. Or in the other case, an experienced member could help you refine your idea. Also, make it a point to look up if the idea or bug you want to work on has already been reported and/or is being worked upon. If yes, you could team up with the person(s) working on it, and help them with testing, or giving ideas.</p> <p>What if you don't have any idea, or you're new to the project altogether? Download it and start using! Try to look around the application to get a sense of what is it about. Don't straight dive into the code. Look for pending issues. Try to assess which issues you could possibly solve. You don't have to solve the complete issue in your head right now. Just think about what all tools you'll need. Do you know how to use them? If still looks difficult at this point, simply try to reproduce the bug. There are many nasty bugs that are hard to reproduce. Even if you come up with a definitive process to reproduce the bug, you'll be doing a great help to whoever takes up the task of fixing it. Share your findings with the team, and follow the discussion. When the bug is finally patched, try reading the diffs and see how it was solved. This will give you idea about <em>at least</em> one component of the application.</p> <p>If submitting patches, feel free to discuss or take help from the community members. Most likely they'll help you out. Never be afraid of code reviews. See them as light discussions. My first code patch was not merged, and the discussion only led me to contributing a better patch. I've recorded the experience below.</p> <h3 id="my-experience">My experience</h3> <p>The first "coding" related issue I had to fix on a KDE project was on KDF. You can see my bug report <a href="https://bugs.kde.org/show_bug.cgi?id=448764">here</a>. KDF was using Dolphin as the default file manager, instead of the system default. It did let users change file manager from settings, but that wouldn't work when using KDF as a Flatpak. So, in my <a href="https://invent.kde.org/utilities/kdf/-/merge_requests/4">first patch</a>, I removed the feature of selecting file manager altogether and made it such that KDF will always use system default file manager. In review, I was suggested to not remove the feature, but instead give users the option to either use default file manager, or specify a custom one.</p> <p>I closed the pull request and the next day, created a <a href="https://invent.kde.org/utilities/kdf/-/merge_requests/5">new one</a>, which was finally merged. My code contribution wasn't something too significant, but it helped me become more confident with QtWidgets, C++, signals - slots and by poking around in the source code, I also learned how the project is structured and how they use their framework to store user preferences. Tiny patch, but big learning. As my <a href="https://invent.kde.org/utilities/kdf/-/merge_requests/7">next patch</a>, I was suggested to add a feature that would detect if application is running as a Flatpak, and disable the custom file manager input automatically. This time I already knew about the application. I sent the patch rather quickly.</p> <p>Of course, I got <em>a lot</em> of help from the community members. The whole experience makes it worth it for me to contribute.</p> <h2 id="going-further">Going further</h2> <p>By now, you probably have some idea about how to go about making your initial contributions to your favorite project.</p> <p>Once you make your first successful contribution, you feel lot more confident. You feel motivated to take on bigger tasks, and become active in discussions. You should have already realized that this is a team effort. You work with constant back and forth reviews and suggestions. The more you participate, the more you learn. Probably for this reason, I like joining different channels and stalking their discussions. (even if I don't understand half the technical terms they use!)</p> <p>This was a beginner sharing his experience for other beginners. Hoping this post cleared up your doubts and you feel more confident about stepping into the world of open source software development!</p> Beginning with Season of KDE 2022 - post #1 Snehit Sah [email protected] http://snehit.dev 2022-01-24T00:00:00+00:00 2022-01-24T00:00:00+00:00 https://snehit.dev/posts/kde/sok-2022/beginning-with-sok-2022/ <h2 id="first-try-ft-failure">First Try (ft. failure)</h2> <p>I usually learn something between semesters when I have holidays. During September - October 2021, I tried learning some Qt and looking around codebase for KDE apps. But something just didn't work out. I suspect my leaning style wasn't correct.</p> <span id="continue-reading"></span><h2 id="transitioning-to-2022">Transitioning to 2022</h2> <p>November - December was very busy, with college asking us to appear in person. I had practicals and exams.</p> <p>Starting Christmas, I was supposed to be free during holidays, and hopefully learn some Qt. Something unexpected happened again. A university society I had joined wanted to push out update to one of their apps. I like Flutter, but the way this team worked was simply not my style. I managed to get it done by 8th Jan, and in a series of crisp conversations made it clear I won't be able to help the society further.</p> <p>During holidays, the SoK announcement mail arrived in my inbox. Most of the ideas were above my knowledge paygrade, but I almost jumped to the ceiling when I saw the word "packaging". No I've never worked with Flatpak before, but I have basic understanding of packaging, and it is in fact, one of the things I take a lot of interest in.</p> <h2 id="flashbacks">Flashbacks</h2> <p>While my first touch with Linux was in 2014, I could use it on my machine only in 2016. One of the most striking features was that you could install any software (subject to availability) along with its dependencies with a single command.</p> <p>Much later in 2019, I finally decided to try and understand how packaging on Linux distros work, because I wanted to package applications for the distro I was using at the time. I failed though.</p> <p>In March 2020, I switched to Endeavour OS and thats when the picture got a lot clearer.</p> <h2 id="pkgbuilds-ft-success-yay">PKGBUILDS ft. success (yay!)</h2> <p>These are build scripts to package applications for pacman, the package manager for Arch Linux. Its stupidly simple to understand, and easy to work with and test.</p> <p>Out of interest, I decided to publish a python application to AUR. With some help from a user on Endeavour OS forum, I was able to get it right and publish.</p> <p>I took some more trivial packages later on. I published my application <a href="https://github.com/flyingcakes85/crabfetch">crabfetch</a> too. I adopted two applications, <a href="https://aur.archlinux.org/packages/maptool-bin/">MapTools</a> and <a href="https://aur.archlinux.org/packages/breaktimer-bin/">BreakTimer</a>. These two are the ones that require regular updates.</p> <h2 id="thanks-to-endeavour-os">Thanks to Endeavour OS...</h2> <p>Back when I signed up on the Endeavour OS forum in April 2020, I didn't expect I'll one day join them. Till date I haven't taken up any task that requires significant effort from me. But I have taken up multiple tiny tasks here and there. I maintain Bspwm and Openbox community editions. Once in a blue moon write tutorial (2 published till yet; one in draft). I do some testing before ISO releases.</p> <p>Frankly speaking, these might be trivial tasks, but working with a group of experienced people was certainly a head start for an 18 year old. There's much to be thankful about. I still get friends asking me "how to get started with open source" and similar questions. I realize Bryan served me the opportunity on a silver platter.</p> <h2 id="on-the-kde-flatpak-matrix-channel">On the KDE Flatpak Matrix channel</h2> <p>The KDE Flatpak channel on Matrix is exactly my liking. My submissions usually got reviews within reasonable time. I packaged some applications before the contribution period officially started. With some help from Aleix Pol and Albert Cid, I was even able to send some patches to KDiskFree, which was my first contrubution to a Qt/C++ application. (thanks!)</p> <p>My mentor is Timothée Ravier. I had a quick chat with him today evening (24th Jan). He briefed me about what all I will be working on during the next two and half months. He's a sweet person to talk with. (thats probably the case with everyone at KDE)</p> <p>Hoping to learn and contribute over the coming weeks. Big thanks to KDE for giving me the chance to work with the team as a part of Season of KDE 2022!</p> <p>Link to project on ideas page : <a href="https://community.kde.org/SoK/Ideas/2022#KDE_Apps_packaging_as_Flatpak_for_Flathub">https://community.kde.org/SoK/Ideas/2022#KDE_Apps_packaging_as_Flatpak_for_Flathub</a></p> <p>Projects announcement: <a href="https://dot.kde.org/2022/01/26/season-kde-kicks">https://dot.kde.org/2022/01/26/season-kde-kicks</a></p> Git Workshop Notes Snehit Sah [email protected] http://snehit.dev 2021-09-14T00:00:00+00:00 2021-09-14T00:00:00+00:00 https://snehit.dev/posts/programming/git-workshop-notes/ <h2 id="about-the-book">About the book</h2> <p>This book is provided in digital format free of cost. You are free to use the content as long as you follow the CC-BY-SA 4.0 license terms.</p> <span id="continue-reading"></span><img src="https://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-sa.png" width="100"> <p><strong>Git Workshop Notes © 2021 by <a href="https://github.com/flyingcakes85">Snehit Sah</a> is licensed under Attribution-ShareAlike 4.0 International. To view a copy of this license, visit <a href="http://creativecommons.org/licenses/by-sa/4.0/">http://creativecommons.org/licenses/by-sa/4.0/</a></strong></p> <p>Any suggestions, typo or errors can be mailed to <a href="mailto:[email protected]">[email protected]</a>.</p> <h2 id="introduction-to-git">Introduction to Git</h2> <h3 id="basics">Basics</h3> <p>Git is an open source distributed version control system.</p> <p>VCS (version control system) refers to a system which can keep track of all the code that is added to a project. Often, you want the history of the project to be preserved for various reasons. Say, the latest version of your software has major bugs, and as a result, you want to rollback some changes to an earlier date. This will only be possible if your code base is version controlled.</p> <p>Git is also called <em>distributed</em> because the code base isn't stored on one server. Instead, each of the developers working on the project can have their own copies of the project. They can make changes independently on their machines, and then request for their changes to be merged back into the original software.</p> <h3 id="why-git">Why Git?</h3> <p>Git is one of the topics covered in MIT's Missing Semester. This course covers multiple useful topics that are oftenly not formally taught, but they can be very useful to students.</p> <p>Git is a vast and powerful software, but <strong>you don't need to be an expert at Git.</strong> You just need to know enought commands to maintain your repository and contribute to other repositories. Rest of the stuff, you can learn as you go.</p> <p>There are two things that I believe are important for open source softwares, and Git helps you realize them.</p> <ol> <li>Integrity of history : The project history is an important data that lets users trust the software. Anyone can see how the softawre developed or when the different components were added. It also lets people track new changes, so that external contributors can focus more on testing new code and also restrict themselves to auditing new code.</li> <li>Long term maintainability : With git, you can associate commits with a descriptive commit message. This lets future maintainers know more about the code. Commits also carry author email - which can be useful in case a maintainer needs to contact a past maintainer to discuss some legacy code.</li> </ol> <h3 id="my-approach-to-git">My approach to Git</h3> <p>I believe many Git workshops get the direction wrong. Their focus is on GitHub; and git is shown as a side utility. I call that the "easy way". Instructor will create a repository. They'll ask viewers to fork the repo, make some minor change via GitHub web interface, and create pull request. Such workshops end with a "grand message" that the viewer made their first PR. Its cool and all, but its severly lacking in some important concepts.</p> <p>I instead prefer bringing Git to the center stage. Git is very powerful, and knowing how to work with the command line utility is going to serve you quite far on your journey. GitHub has a cool self explanatory UI - do you really need to forum more over learning that as compared to a powerful command line utility?</p> <p>Another minor complaint with having all focus on GitHub is that new students fail to appreciate the existence of other git repository hosting services. Truth is that once you learn Git, you can work with any hosting service.</p> <h3 id="a-note-about-git-gui-programs">A note about Git GUI programs</h3> <p>I'm not against GUI programs altogether. Once in a blue moon, even I fall back to using GUI. Hovever, while learning its better to use command line client only. That way you know what is happening and it stregthens your understanding.</p> <p>PS. Recorded lectures from The Missing Semester are free to view. You can check out their website here : <a href="https://missing.csail.mit.edu/">https://missing.csail.mit.edu/</a>.</p> <h2 id="starting-with-git">Starting with Git</h2> <p>We already know that Git tracks your project. So, every time you change a file and commit it to the project (basically asking Git to mark a milestone you can return to later, if needed), Git is recording the <strong>changes</strong> you made to each file. Note that complete files are not duplicated. Only the changes you made to each file are stored by Git. It is intelligent enough to create the complete file by knowing the changes you made all through.</p> <h3 id="installing">Installing</h3> <p>Downloads are offered at git-scm website. Windows users should download installer from the website. Users on *nix systems can use their package manager for the same.</p> <p><a href="https://git-scm.com/downloads">https://git-scm.com/downloads</a></p> <p>To check if git is woring, open a terminal, and run</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git --version </span></code></pre> <p>This should output the version name. An example output, on my system:</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>git version 2.33.0 </span></code></pre> <p>I'm starting with shell commands now. Git commands should work on all systems, but other commands like <code>echo</code> will probably work only on *nix based systems. May also in Git Bash on Windows.</p> <h3 id="setting-up-git">Setting up Git</h3> <p>Git needs some info to create commits. At the very least, it needs to know your name and email. Run the following commands to set them up.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> config</span><span style="color:#bf616a;"> --global</span><span> user.name &quot;</span><span style="color:#a3be8c;">Your Name</span><span>&quot; </span><span style="color:#bf616a;">git</span><span> config</span><span style="color:#bf616a;"> --global</span><span> user.email &quot;</span><span style="color:#a3be8c;">[email protected]</span><span>&quot; </span></code></pre> <p>You can verify them too. I have shown the commands with their outputs.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired ~</span><span>]$ git config</span><span style="color:#bf616a;"> --global</span><span> user.name </span><span style="color:#bf616a;">Snehit</span><span> Sah </span><span style="color:#bf616a;">[snehit@wired ~</span><span>]$ git config</span><span style="color:#bf616a;"> --global</span><span> user.email </span><span style="color:#bf616a;">[email protected] </span></code></pre> <p>You may also change the default init branch to something other than <code>master</code>.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> config</span><span style="color:#bf616a;"> --global</span><span> init.defaultBranch main </span></code></pre> <p>You can replace <code>main</code> with any other name you like. This step is not necessary. Do this only if you don't want your default branches in new repositories to be named <code>master</code>.</p> <h3 id="initializing-a-repository">Initializing a repository</h3> <p>Create a new folder. Change working directory to this new folder. And then initialize a new repository.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">mkdir</span><span> my-project </span><span style="color:#96b5b4;">cd</span><span> my-project </span><span style="color:#bf616a;">git</span><span> init </span></code></pre> <p>Now, you can open your code editor in this folder. Any files you add here will automatically be noticed by git. I run the following command to launch VS Code in my repo.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">code</span><span> . </span></code></pre> <h3 id="adding-files">Adding files</h3> <p>You can either create files via a text editor like VS Code, or even the classic notepad, or you can use a terminal utility to create files. I'll use <code>echo</code> to create a simple python script.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;Hello World&#39;)</span><span>&quot; &gt; test.py </span></code></pre> <p>It creates a file <code>test.py</code> with the code <code>print('Hello World')</code>.</p> <p>Now, lets check if git notices this file or not. Run <code>git status</code> in the same folder, and you should get such an ouput.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git status </span><span style="color:#bf616a;">On</span><span> branch main </span><span> </span><span style="color:#bf616a;">No</span><span> commits yet </span><span> </span><span style="color:#bf616a;">Untracked</span><span> files: </span><span> (</span><span style="color:#bf616a;">use </span><span>&quot;</span><span style="color:#a3be8c;">git add &lt;file&gt;...</span><span>&quot; to include in what will be committed) </span><span> </span><span style="color:#bf616a;">test.py </span><span> </span><span style="color:#bf616a;">nothing</span><span> added to commit but untracked files present </span><span>(</span><span style="color:#bf616a;">use </span><span>&quot;</span><span style="color:#a3be8c;">git add</span><span>&quot; to track) </span></code></pre> <p>There is quite some information here. The first line tells we are on this branch called <code>main</code>. Don't worry if you don't know what branches are. I'll discuss it soon.</p> <p>Next is a section called <code>Untracked files</code>. This lists the file that are there in folder, but git isn't yet tracking them for changes. Our file, <code>test.py</code> is listed there. Git is also telling us a command to start tracking them... So lets move on to that.</p> <h3 id="adding-files-to-staging">Adding files to staging</h3> <p>Run this command to start tracking <code>test.py</code>.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> add test.py </span></code></pre> <p><code>git add</code> serves two purposes. If a file is untracked, then it will start tracking it and add to staging area. If a file is already being tracked, but has some changes, then git will simply just add the file to staging area.</p> <p>What is the staging area, you ask? Its the files whose change will be recorded and stored when you run git commit the next time.</p> <p>Before we move on to the next command, let's see the output of <code>git status</code> after running the above <code>git add</code> command.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git status </span><span style="color:#bf616a;">On</span><span> branch main </span><span> </span><span style="color:#bf616a;">No</span><span> commits yet </span><span> </span><span style="color:#bf616a;">Changes</span><span> to be committed: </span><span> (</span><span style="color:#bf616a;">use </span><span>&quot;</span><span style="color:#a3be8c;">git rm --cached &lt;file&gt;...</span><span>&quot; to unstage) </span><span> </span><span style="color:#bf616a;">new</span><span> file: test.py </span></code></pre> <p>Our file <code>test.py</code> is now listed under a different section - <code>Changes to be committed</code>.</p> <p>If you have multiple files in a project, you can simply use the following command to add all changed and untracked files.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> add</span><span style="color:#bf616a;"> -A </span></code></pre> <p>Be careful while running this. It may possibly add any extra files you created in the repository which you actually don't want in commits.</p> <h3 id="committing-changes">Committing changes</h3> <p>Once you have files in the staging area, you <code>commit</code>. This is an important step. Note that commits are the mechanism by which git is able to preserve history. You can see commits as milestones, which anyone can check out.</p> <p>Commits are acompained by at least a title, and an optional message. Try to keep the message/title short, yet informative. For larger projects, it becomes necessary to have informative commit messages so that reviewers know what the commit does.</p> <p>Run this in the terminal</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> commit </span></code></pre> <p>This should land you in a text editor, usually vi(m), where you add commit title and message. This is what you should see.</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span> </span><span># Please enter the commit message for your changes. Lines starting </span><span># with &#39;#&#39; will be ignored, and an empty message aborts the commit. </span><span># </span><span># On branch main </span><span># </span><span># Initial commit </span><span># </span><span># Changes to be committed: </span><span># new file: test.py </span><span># </span></code></pre> <p>This is giving the output you saw with <code>git status</code> one more time, so that you can be sure that you are committing all the files you want. On the first line, give a commit title. Leave a blank line, and from the third line, you can write the description.</p> <p>Here is an example. Note that I did not remove the lines that were already there. They are starting with a '#' and git will ignore them.</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>Add test.py with basic code </span><span> </span><span>New beginnings - This file prints </span><span>Hello World. Tested with Python3.7 </span><span># Please enter the commit message for your changes. Lines starting </span><span># with &#39;#&#39; will be ignored, and an empty message aborts the commit. </span><span># </span><span># On branch main </span><span># </span><span># Initial commit </span><span># </span><span># Changes to be committed: </span><span># new file: test.py </span><span># </span></code></pre> <p>Save and close the file. Git should create a commit now, and print some message in the terminal.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git commit </span><span style="color:#bf616a;">[main</span><span> (root-commit) </span><span style="color:#bf616a;">5de911e]</span><span> Add test.py with basic code </span><span> </span><span style="color:#bf616a;">1</span><span> file changed, 1 insertion(+) </span><span> </span><span style="color:#bf616a;">create</span><span> mode 100644 test.py </span></code></pre> <p>Its called <code>root-commit</code> because its the first commit in this repo. There is a fancy alphanumeric string following it. <code>5de911e</code> - these are the first few characters of the commit hash. Commit hash is a 20 character alphanumeric SHA1 hash that is generated using data from past commit, changes in current commit, timestamp, author info etc. These hashes are git's primary mechanism to detect any changes to past code.</p> <p>If you don't want to add a desription to your commit - maybe because the change is very minor and self explanatory - you can use the shorthand to just add a commit title.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> -m </span><span>&quot;</span><span style="color:#a3be8c;">Fix typo in code</span><span>&quot; </span></code></pre> <h3 id="checking-logs">Checking logs</h3> <p>Since we have made a commit, its a permanent part of the repository now. You can see logs to verify the commit is there.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git log </span><span style="color:#bf616a;">commit</span><span> 5de911e18db087d3c3a57031dab49637e316608f (HEAD -&gt; main) </span><span style="color:#bf616a;">Author:</span><span> Snehit Sah &lt;[email protected]&gt; </span><span style="color:#bf616a;">Date:</span><span> Thu Sep 9 12:12:00 2021 +0530 </span><span> </span><span> </span><span style="color:#bf616a;">Add</span><span> test.py with basic code </span><span> </span><span> </span><span style="color:#bf616a;">New</span><span> beginnings - This file prints </span><span> </span><span style="color:#bf616a;">Hello</span><span> World. Tested with Python3.7 </span></code></pre> <p>This gives us information about the commit we just made. As we make more commits, the log will grow lager. In the first line, you have the complete commit hash. (in the last section, we only saw first 7 characters). We also have information about the author, commit date/time and message. If you are not interested in author info, and just want to see commit messages, we can use the shorter format with <code>git log --oneline</code></p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git log</span><span style="color:#bf616a;"> --oneline </span><span style="color:#bf616a;">5de911e</span><span> (HEAD -&gt; main) </span><span style="color:#bf616a;">Add</span><span> test.py with basic code </span></code></pre> <p>This is more useful to know how the project grew, since it omits author info, dates and commit description.</p> <h3 id="amending-last-commit">Amending last commit</h3> <p>Sometimes it happens that you forgot to add a file to staging before commit, or there's a tiny change you need to make, which should have been a part of the last commit. In such situations, git provides an easy way to amend last commit. Assuming you made a commit, do some edits to code. Then do <code>git add</code> as usual. While committing, include the <code>--amend</code> flag to instruct git to update the last commit instead of creating a new one.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> --amend </span></code></pre> <p>If you look at the log, you will see the commit hash changes. This signifies that <em>some</em> changes were made. Later on when you upload your code on the internet, these hashes will allow other collaborators ensure they have the same code as you. If you edit a past comment and upload it, then other collaborators will get to know about it. In general, its not a good idea to amend/edit commits if you have published them onto the web. Do this only if the commits to be edited are only on your local machine. One exception is that when you accidently commited and published sesnsitive info, like access keys, password etc.</p> <p>PS. In case you are wondering if other collaborators will match commit hash letter by letter to verify integrity - the answer is an obvious "no!". Git does that automatically.</p> <h3 id="recap">Recap</h3> <p>Try creating another file, and make some changes to <code>test.py</code>. Check status. Add both files to staging, and then make a commit. Check log to verify the commit was made.</p> <p>You can use any text editor for the task. I'll quickly give the relevant shell commands for those who want to follow along in the shell.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;New file&#39;)</span><span>&quot; &gt; new_file.py </span><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;Another line&#39;)</span><span>&quot; &gt;&gt; test.py </span></code></pre> <p>Output of <code>git status</code> at this stage.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git status </span><span style="color:#bf616a;">On</span><span> branch main </span><span style="color:#bf616a;">Changes</span><span> not staged for commit: </span><span> (</span><span style="color:#bf616a;">use </span><span>&quot;</span><span style="color:#a3be8c;">git add &lt;file&gt;...</span><span>&quot; to update what will be committed) </span><span> (</span><span style="color:#bf616a;">use </span><span>&quot;</span><span style="color:#a3be8c;">git restore &lt;file&gt;...</span><span>&quot; to discard changes in working directory) </span><span> </span><span style="color:#bf616a;">modified:</span><span> test.py </span><span> </span><span style="color:#bf616a;">Untracked</span><span> files: </span><span> (</span><span style="color:#bf616a;">use </span><span>&quot;</span><span style="color:#a3be8c;">git add &lt;file&gt;...</span><span>&quot; to include in what will be committed) </span><span> </span><span style="color:#bf616a;">new_file.py </span><span> </span><span style="color:#bf616a;">no</span><span> changes added to commit (use &quot;</span><span style="color:#a3be8c;">git add</span><span>&quot; and/or &quot;</span><span style="color:#a3be8c;">git commit -a</span><span>&quot;) </span></code></pre> <p>Continuing on to add files and commit them.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> add new_file.py </span><span style="color:#bf616a;">git</span><span> add test.py </span><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> -m </span><span>&quot;</span><span style="color:#a3be8c;">Update test.py and add new code</span><span>&quot; </span></code></pre> <p>Ouptut of <code>git log</code></p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git log </span><span style="color:#bf616a;">commit</span><span> 9c804c05610ca86f720abda62b297e9d2e6a725f (HEAD -&gt; main) </span><span style="color:#bf616a;">Author:</span><span> Snehit Sah &lt;[email protected]&gt; </span><span style="color:#bf616a;">Date:</span><span> Thu Sep 9 12:34:49 2021 +0530 </span><span> </span><span> </span><span style="color:#bf616a;">Update</span><span> test.py and add new code </span><span> </span><span style="color:#bf616a;">commit</span><span> 5de911e18db087d3c3a57031dab49637e316608f </span><span style="color:#bf616a;">Author:</span><span> Snehit Sah &lt;[email protected]&gt; </span><span style="color:#bf616a;">Date:</span><span> Thu Sep 9 12:12:00 2021 +0530 </span><span> </span><span> </span><span style="color:#bf616a;">Add</span><span> test.py with basic code </span><span> </span><span> </span><span style="color:#bf616a;">New</span><span> beginnings - This file prints </span><span> </span><span style="color:#bf616a;">Hello</span><span> World. Tested with Python3.7 </span></code></pre> <h3 id="using-gitignore-file">Using gitignore file</h3> <p>You may have some files in your project directory which you don't want git to track. For example, upon testing C/C++ apps, you have a binary that shouldn't be there with the code. To prevent them from accidently being committed, you can add them to gitignore file. You'll first have to create a file named <code>.gitignore</code> in the root of your repo folder. Then you list the file paths that should not be tracked.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">*/a.out</span><span>&quot; &gt;&gt; .gitignore </span></code></pre> <p>This will prevent git from tracking any file with name <code>a.out</code>. The aesterix at beginning is a wildcard that will select any path where <code>a.out</code> exists. To add folders, append a forward slash after path.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">build/</span><span>&quot; &gt;&gt; .gitignore </span></code></pre> <h2 id="working-with-remotes">Working with remotes</h2> <p>Up until now, we have been working on our local system. Git however is built to facilitate collaboration of multiple developers. To let other developers work on our code, we need to publish this code to a website.</p> <p>Now, you can upload your code anywhere. Zip it up and put on cloud storage like Google Drive or Dropbox. Or send the files as an attachment to your friend. There are many ways, but they won't preserve the commit history and messages (unless you include the hidden <code>.git</code> folder). Moreover, it will be difficult to use collaboration features of git.</p> <p>It is much better to use a hosting service that is specially made for Git repositories. One of them is GitHub and thats the one which we will be using for this tutorial.</p> <p>Head over to their sign up page and create an account if not done already. <a href="https://github.com/join">https://github.com/join</a></p> <h3 id="connecting-a-remote-repository">Connecting a remote repository</h3> <p>Create a new GitHub repository at <a href="https://github.com/new">https://github.com/new</a>. Give it a name. Description is optional. Make sure that all checkboxes under initialization are unchecked.</p> <p><img src="/blog/assets/images/post/github-new-repo.png" alt="" title="GitHub New Repo" /></p> <p>Create the repository. On the page you are redirected to, you have an https link under <em>Quick setup</em>.</p> <p>Link is of the form <code>https://github.com/&lt;username&gt;/&lt;repo-name&gt;.git</code>. Copy this link.</p> <p>In your terminal, you will now tell git to use this remote link for publishing on the internet. You use the <code>git remote add</code> command to do this.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> remote add origin https://github.com/flyingcakes85/my-project.git </span></code></pre> <p>Here, <code>origin</code> specifies the remote name. You can give it any name. <code>origin</code> is a common name for the primary remote location. Make sure you use your repo link in the command.</p> <p>Before you push your branch, you first need an access token. Think of it as an alternate password to your account. For security reasons, using your actual password is not supported on GitHub. SSH is the easier way, but setting it up is out of the scope of this tutorial.</p> <p>Head over to this link : <a href="https://github.com/settings/tokens">https://github.com/settings/tokens</a>. Click on "Generate new token". It may ask your password again.</p> <p>Add a note to identify the token later. Check the first box which says "repo". It should automatically check the 5 boxes under it. Scroll down and click "Generate token". You will be redirected back to the token page where you can see your newly created token. Copy it to a file and store it somewhere you can access. While pushing form the terminal, you will use this token instead of your password.</p> <p>Finally, you can push your branch to the remote.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> push</span><span style="color:#bf616a;"> -u</span><span> origin main </span></code></pre> <p>It will ask your username and password. Enter your GitHub username only (not the complete link) and for password, use the token we just generated. Now on in this tutorial, I won't mention that you have to use this token, so keep it in mind.</p> <p><code>-u</code> is a shorthand for <code>--set-upstream</code>. It tells git that <code>origin</code> is the upstream for <code>main</code> i.e. the remote location where the <code>main</code> branch should be published. You might be wondering why we need to tell this? Git can work with multiple remotes, and often, different branches need to be published to different remotes. For any future push on this branch, you don't need to mention upstream, and simply running <code>git push</code> should do tho work for you.</p> <h3 id="pulling-remote-changes">Pulling remote changes</h3> <p>Say someone else contributed to your repository. The changes they contributed will be stored on GitHub (or whichever remote you are using). You need to get the changes down on your machine. <code>git pull</code> is the command we use to get changes from remote to our local system.</p> <p>Since we may not be able to find a contributor right away, so let us make changes ourselves on the remote. GitHub web interface allows making changes to code without needing to have repository on your local system. Head over to the repository on your GitHub account.</p> <p>You will be able to see the files you added - <code>test.py</code> and <code>new_file.py</code>. Click on any of them, let's say <code>test.py</code>. You will see the code you wrote. On top right of the code, you can see a pencil icon that lets you make changes to file.</p> <p><img src="/blog/assets/images/post/file-edit.png" alt="" title="file-edit" /></p> <p>Add a some code and click "Commit changes".</p> <p><img src="/blog/assets/images/post/commit-web.png" alt="" title="commit web" /></p> <p>Now, if you go to repository page, and click on the number of commits (see screengrab below), you can see 3 commits listed. We made 2 commits earlier. The third commit was made just now via GitHub web.</p> <p><img src="/blog/assets/images/post/commit-history.png" alt="" title="commit web" /></p> <p>Go back to the terminal and run <code>git log --oneline</code>. You will still see only 2 commits here. This mean we need to pull remote commits on to our local machine. Run <code>git pull</code> to do the same. Here is the output in my case</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git pull </span><span style="color:#bf616a;">remote:</span><span> Enumerating objects: 5, done. </span><span style="color:#bf616a;">remote:</span><span> Counting objects: 100% (5/5)</span><span style="color:#bf616a;">,</span><span> done. </span><span style="color:#bf616a;">remote:</span><span> Compressing objects: 100% (3/3)</span><span style="color:#bf616a;">,</span><span> done. </span><span style="color:#bf616a;">remote:</span><span> Total 3 (delta 0)</span><span style="color:#bf616a;">,</span><span> reused 0 (delta 0)</span><span style="color:#bf616a;">,</span><span> pack-reused 0 </span><span style="color:#bf616a;">Unpacking</span><span> objects: 100% (3/3)</span><span style="color:#bf616a;">,</span><span> 709 bytes | </span><span style="color:#bf616a;">35.00</span><span> KiB/s, done. </span><span style="color:#bf616a;">From</span><span> https://github.com/flyingcakes85/my-project </span><span> </span><span style="color:#bf616a;">9c804c0..7e8fc14</span><span> main -&gt; origin/main </span><span style="color:#bf616a;">Updating</span><span> 9c804c0..7e8fc14 </span><span style="color:#bf616a;">Fast-forward </span><span> </span><span style="color:#bf616a;">test.py </span><span>| </span><span style="color:#bf616a;">2</span><span> ++ </span><span> </span><span style="color:#bf616a;">1</span><span> file changed, 2 insertions(+) </span></code></pre> <p>You can see the text <code>test.py | 2 ++</code>. This mean that there were 2 additions made to this file. Deletions are followed by <code>--</code>. Now, if you run <code>git log --oneline</code> in terminal, you can see third commit too.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git log</span><span style="color:#bf616a;"> --oneline </span><span style="color:#bf616a;">7e8fc14</span><span> (HEAD -&gt; main, origin/main) </span><span style="color:#bf616a;">Update</span><span> test.py </span><span style="color:#bf616a;">9c804c0</span><span> Update test.py and add new code </span><span style="color:#bf616a;">5de911e</span><span> Add test.py with basic code </span></code></pre> <h3 id="listing-remotes">Listing remotes</h3> <p>You can use <code>git remote</code> to list remote names configured for current repo, or pass the <code>-v</code> flag to also list remote links.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git remote </span><span style="color:#bf616a;">origin </span><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git remote</span><span style="color:#bf616a;"> -v </span><span style="color:#bf616a;">origin</span><span> https://github.com/flyingcakes85/my-project.git (fetch) </span><span style="color:#bf616a;">origin</span><span> https://github.com/flyingcakes85/my-project.git (push) </span></code></pre> <h3 id="using-git-clone">Using git clone</h3> <p>So far we created a repository on the command line and connected it to a remote. Many times, we already have a git repo online which we want to use on our local machine. You can simply use the <code>git clone</code> command to download a repository. Note that you can download any public repository with this command even if you did not create it.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> clone https://github.com/flyingcakes85/my-project.git </span></code></pre> <p>Often, the repository you want to download is large, and downloading it can take some time. To get around this, you can use <code>--depth=N</code> flag to fetch only the past <code>N</code> commits. You will have all files from the repository, but you won't have complete commit history.</p> <h3 id="editing-pushlished-commits">Editing pushlished commits</h3> <p>Make some changes to a file an instead of a new commit, use <code>--amend</code> to edit the last commit.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;More content&#39;)</span><span>&quot; &gt;&gt; new_file.py </span><span style="color:#bf616a;">git</span><span> add new_file.py </span><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> --amend </span></code></pre> <p>Now, if you do a <code>git push</code>, you will get an error.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git push </span><span style="color:#bf616a;">Username</span><span> for &#39;</span><span style="color:#a3be8c;">https://github.com</span><span>&#39;: flyingcakes85 </span><span style="color:#bf616a;">Password</span><span> for &#39;</span><span style="color:#a3be8c;">https://[email protected]</span><span>&#39;: </span><span> </span><span style="color:#bf616a;">To</span><span> https://github.com/flyingcakes85/my-project.git </span><span> ! </span><span style="color:#bf616a;">[rejected]</span><span> main -&gt; main (non-fast-forward) </span><span style="color:#bf616a;">error:</span><span> failed to push some refs to &#39;</span><span style="color:#a3be8c;">https://github.com/flyingcakes85/my-project.git</span><span>&#39; </span><span style="color:#bf616a;">hint:</span><span> Updates were rejected because the tip of your current branch is behind </span><span style="color:#bf616a;">hint:</span><span> its remote counterpart. Integrate the remote changes (e.g. </span><span style="color:#bf616a;">hint: </span><span>&#39;</span><span style="color:#a3be8c;">git pull ...</span><span>&#39;) </span><span style="color:#bf616a;">before</span><span> pushing again. </span><span style="color:#bf616a;">hint:</span><span> See the &#39;</span><span style="color:#a3be8c;">Note about fast-forwards</span><span>&#39; in &#39;</span><span style="color:#a3be8c;">git push --help</span><span>&#39; for details. </span></code></pre> <p>There are two ways to get out of this situation - you either do a <code>git pull --rebase</code> to merge remote changes to your local copy first. Or you can do <code>git push -f</code> to force overwrite remote with your code.</p> <p>If you were to do the latter, you will be changing the history of project. Anyone who has a copy of the project and does <code>git pull</code> will get a similar error.</p> <p>The above error is a also common error when you made some change on your remote (via web interface) and then you made some commits on your local machine without pulling remote changes first. As I told, <code>git pull --rebase</code> should get you out of the fix in most cases.</p> <p>Keep in mind, editing published commits is not recommended, and you should do this only when necessary.</p> <h2 id="working-with-branches">Working with Branches</h2> <p>Git provides the ability to create branches so as to let developers work on new features or bugfix without disturbing the main code. Changes you make to a branch are stored separately from the other branches. You can switch between branches anytime. When you think you have made enough changes to a branch and the changes are working, you can merge the branch into your <code>main</code> branch.</p> <h3 id="listing-branches">Listing branches</h3> <p><code>git branch</code> will show you your local branches, and adding the <code>-a</code> flag will also list remote branches.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git branch </span><span style="color:#bf616a;">*</span><span> main </span><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git branch</span><span style="color:#bf616a;"> -a </span><span style="color:#bf616a;">*</span><span> main </span><span> </span><span style="color:#bf616a;">remotes/origin/main </span></code></pre> <p>The branch marked with an aesterix denotes the currently active branch. Any changes or commits you make are added on the currently active branch.</p> <h3 id="creating-and-switching-branches">Creating and switching branches</h3> <p><code>git branch &lt;name&gt;</code> creates a new branch. <code>git checkout &lt;name&gt;</code> will switch to the new branch so that further changes are make to the new branch.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> branch add-emotes </span><span style="color:#bf616a;">git</span><span> checkout add-emotes </span></code></pre> <p>You can also use the shorthand to create and switch branch in one command. Just use the <code>checkout</code> command with a <code>-b</code> flag.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git checkout</span><span style="color:#bf616a;"> -b</span><span> add-emotes </span><span style="color:#bf616a;">Switched</span><span> to a new branch &#39;</span><span style="color:#a3be8c;">add-emotes</span><span>&#39; </span></code></pre> <p>You can also <em>checkout</em> an older commit. This will replace the project files with the content that existed at that commit. Run <code>git log --oneline</code> to see the commit hashes.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git log</span><span style="color:#bf616a;"> --oneline </span><span style="color:#bf616a;">f15f7dc</span><span> (HEAD -&gt; bugfix, origin/main, main, add-emotes) </span><span style="color:#bf616a;">Update</span><span> test.py </span><span style="color:#bf616a;">7e8fc14</span><span> Update test.py </span><span style="color:#bf616a;">9c804c0</span><span> Update test.py and add new code </span><span style="color:#bf616a;">5de911e</span><span> Add test.py with basic code </span></code></pre> <p>Note the hash of whichever commit you want to checkout. Say, we want to go to the first commit. Its hash is <code>5de911e</code>.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> checkout 5de911e </span></code></pre> <p>This will land you to the first commit. If you see the project now, you will find only one file. Don't worry, our changes aren't lost. We can just switch to <code>main</code> branch to get our changes back.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> checkout main </span></code></pre> <h3 id="working-on-branches-merging-and-stash">Working on branches - merging and stash</h3> <p>You usually create a branch to work on bug or feature without disturbing the actual code. The benefit here is that if there are any urgent changes required to the main code, you can make commits on main without needing to halt working on bug or feature.</p> <p>There are usually three situations.</p> <h4 id="fast-forward-merge">Fast forward merge</h4> <p>First checkout the newly created <code>add-emotes</code> branch.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> checkout add-emotes </span></code></pre> <p>Lets make some changes now.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;:-)&#39;)</span><span>&quot; &gt;&gt; emotes.py </span><span style="color:#bf616a;">git</span><span> add emotes.py </span><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> -m </span><span>&quot;</span><span style="color:#a3be8c;">Add emotes</span><span>&quot; </span></code></pre> <p>You test the code. It works and you are satisfied. So you decide to merge it into main. First checkout <code>main</code> branch then merge the other branch into it.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git checkout main </span><span style="color:#bf616a;">Switched</span><span> to branch &#39;</span><span style="color:#a3be8c;">main</span><span>&#39; </span><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git merge add-emotes </span><span style="color:#bf616a;">Updating</span><span> f15f7dc..e74906b </span><span style="color:#bf616a;">Fast-forward </span><span> </span><span style="color:#bf616a;">emotes.py </span><span>| </span><span style="color:#bf616a;">1</span><span> + </span><span> </span><span style="color:#bf616a;">1</span><span> file changed, 1 insertion(+) </span><span> </span><span style="color:#bf616a;">create</span><span> mode 100644 emotes.py </span></code></pre> <p>Notice the phrase <code>Fast-forward</code>. It signifies that no commits were made on main from the time of creating branch <code>add-emotes</code> and the time when we merged it. Git could just "fast-forward" the <code>main</code> branch with commits from <code>add-emotes</code>. You ran use <code>git log --oneline</code> to verify that the commit was indeed applied on <code>main</code> branch too.</p> <h4 id="recursive-merge">Recursive merge</h4> <p>Lets do this process again, but we will make a commit on <code>main</code> before merging. Again, checkout <code>add-emotes</code> and make some changes.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> checkout add-emotes </span><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;:/&#39;)</span><span>&quot; &gt;&gt; emotes.py </span></code></pre> <p>Let's say, you don't want to commit now, as you want to make more changes. But there's an important fix to make on the <code>main</code> branch. You can go forward and switch branch, but it can become messy, because the changes will also show up on main (they are uncommitted) and it will get confusing for you. So, you store the changes to a temporary directory and then make changes on main.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> stash </span></code></pre> <p>Upon running this, you will notice that the line we added to <code>emotes.py</code> is no longer there. Now make changes on main and commit.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> checkout main </span><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;important bugfix&#39;)</span><span>&quot; &gt;&gt; test.py </span><span style="color:#bf616a;">git</span><span> add test.py </span><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> -m </span><span>&quot;</span><span style="color:#a3be8c;">Important Bugfix</span><span>&quot; </span></code></pre> <p>Now, let's switch back to <code>add-emotes</code> branch and complete our code. We use the <code>git stash pop</code> command to bring back the changes we had made earlier.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> checkout add-emotes </span><span style="color:#bf616a;">git</span><span> stash pop </span><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;B-)&#39;)</span><span>&quot; &gt;&gt; emotes.py </span><span style="color:#bf616a;">git</span><span> add emotes.py </span><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> -S -m </span><span>&quot;</span><span style="color:#a3be8c;">Add more emotes</span><span>&quot; </span></code></pre> <p>Now, lets switch back to <code>main</code> branch and try merging <code>add-emotes</code>.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> checkout main </span><span style="color:#bf616a;">git</span><span> merge add-emotes </span></code></pre> <p>This will land you in your text editor, with the following text.</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>Merge branch &#39;add-emotes&#39; </span><span># Please enter a commit message to explain why this merge is necessary, </span><span># especially if it merges an updated upstream into a topic branch. </span><span># </span><span># Lines starting with &#39;#&#39; will be ignored, and an empty message aborts </span><span># the commit. </span></code></pre> <p>This is very much like making a commit. This time, there was already a commit made on to <code>main</code> before we merged the branch. So, git cannot simply fast forward. Save this file and exit. You should get this message.</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>Merge made by the &#39;recursive&#39; strategy. </span><span> emotes.py | 2 ++ </span><span> 1 file changed, 2 insertions(+) </span></code></pre> <p>This time, it was not fast forwarded. Git used a different strategy called recursive.</p> <h4 id="merge-conflict">Merge conflict</h4> <p>Finally, if you change the same line of the same file in both branch then try to merge them, you run into a merge conflict. Let's quickly add different text to the same file on both <code>main</code> branch and <code>add-emotes</code> branch.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> checkout main </span><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;added via main&#39;)</span><span>&quot; &gt;&gt; test.py </span><span style="color:#bf616a;">git</span><span> add test.py </span><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> -m </span><span>&quot;</span><span style="color:#a3be8c;">Make program better</span><span>&quot; </span><span style="color:#bf616a;">git</span><span> checkout add-emotes </span><span style="color:#96b5b4;">echo </span><span>&quot;</span><span style="color:#a3be8c;">print(&#39;added via add-emotes&#39;)</span><span>&quot; &gt;&gt; test.py </span><span style="color:#bf616a;">git</span><span> add test.py </span><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> -m </span><span>&quot;</span><span style="color:#a3be8c;">Make program fancy</span><span>&quot; </span></code></pre> <p>If you see the contents of <code>test.py</code>, you won't see the line <code>print('added via main')</code>. If you checkout <code>main</code>, then you won't see <code>print('added via add-emotes')</code>. So, what we have got is different content at same location in two branches. This will lead to a conflict.</p> <p>First checkout <code>main</code> branch.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> checkout main </span></code></pre> <p>Lets now merge it and see what happens.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">[snehit@wired</span><span> my-project]$ git merge add-emotes </span><span style="color:#bf616a;">Auto-merging</span><span> test.py </span><span style="color:#bf616a;">CONFLICT</span><span> (content)</span><span style="color:#96b5b4;">:</span><span> Merge conflict in test.py </span><span style="color:#bf616a;">Automatic</span><span> merge failed; </span><span style="color:#bf616a;">fix</span><span> conflicts and then commit the result. </span></code></pre> <p>Git bailed out saying it cannot merge - as we expected.</p> <p>When you get a merge conflict, you shouln't need to panic. Its not an "error". It only indicates that git is unable to decide which copy of the code to keep, because the two branches have different changes for the same file location.</p> <p>Git is telling us that there is a conflict in <code>test.py</code>. Lets open that file and see what's there.</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>print(&#39;Hello World&#39;) </span><span>print(&#39;Another line&#39;) </span><span> </span><span>print(&#39;Added via GitHub web&#39;) </span><span>&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD </span><span>print(&#39;important bugfix&#39;) </span><span>print(&#39;added via main&#39;) </span><span>======= </span><span>print(&#39;added via add-emotes&#39;) </span><span>&gt;&gt;&gt;&gt;&gt;&gt;&gt; add-emotes </span></code></pre> <p>Here, you can see the conflicting part between angled brackets. From <code>&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD</code> to <code>=======</code> are the contents that are in <code>main</code>. From <code>=======</code> to <code>&gt;&gt;&gt;&gt;&gt;&gt;&gt; add-emotes</code> are the contents that are in <code>add-emotes</code>. you can freely remove one of them, along with the angled brackets and equal signs. You may also just remove the brackets and equal signs in case you want to keep changes from both branches. Finally, you may remove it to add some other code altogether. Its all up to you.</p> <p>Lets say, I remove the code from <code>main</code>. So my file should now look like this.</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>print(&#39;Hello World&#39;) </span><span>print(&#39;Another line&#39;) </span><span> </span><span>print(&#39;Added via GitHub web&#39;) </span><span> </span><span>print(&#39;added via add-emotes&#39;) </span></code></pre> <p>Now we can continue on to adding file and committing it.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> add test.py </span><span style="color:#bf616a;">git</span><span> commit</span><span style="color:#bf616a;"> -m </span><span>&quot;</span><span style="color:#a3be8c;">Merge add-emotes into main</span><span>&quot; </span></code></pre> <p>This will create the merge commit.</p> <h3 id="deleting-branches">Deleting branches</h3> <p>You may want to delete a branch if you have merged it into <code>main</code> and it is no longer needed. Or maybe you decided against incorporating the changes from that branch. In these cases, you can delete the branch.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> branch</span><span style="color:#bf616a;"> -d </span><span>&lt;name&gt; </span></code></pre> <p>If you had published a branch you now want to delete, run this command</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">git</span><span> push origin</span><span style="color:#bf616a;"> --delete </span><span>&lt;branch name&gt; </span></code></pre> <p>Run these commands with care, as you may accidently delete one of the important branches.</p> <h2 id="beyond-the-book">Beyond the book</h2> <h3 id="general-development-workflow">General development workflow</h3> <p>I'll briefly tell the workflow you follow when contributing to someone else's repo. You first fork the repository to your account. You clone your fork with <code>git clone &lt;link&gt;</code>. You will then create a new branch which shall hold the commits you make. You can also directly make commits on <code>main</code>, but this is almost <strong>never</strong> recommended.</p> <p>You make some changes then commit it. When you think you have made all the changes you wanted, you push the branch to remote on your repo, using <code>git push -u origin &lt;branch name&gt;</code>. On GitHub, you finally create a pull request from your branch to the <code>main</code> or <code>dev</code> branch of original repo.</p> <p>Maintainers will often have a separate <code>dev</code> branch. This can be for various reasons - the simplest one being that they don't want everyone to be using the latest changes by default as it can be buggy and unstable. Those who want to test new features can manually switch to dev branch and use. Once features from dev branch are tested, it is finally merged into <code>main</code>.</p> <p>If available, read the <code>CONTRIBUTING.md</code> file on the original repo.</p> <h3 id="referencing-github-pull-requests-issues">Referencing GitHub pull requests/issues</h3> <p>Say your pull request fixes a certain issue open on the original repository. You can add <code>Fixes #N</code> to your commit description. Here <code>N</code> is a number that shows just after the issue title. The numbers also show up on pull request titles. You can use the same <code>#N</code> format to reference a certain pull request or issue while adding commits on GitHub.</p> Love, Alexa Snehit Sah [email protected] http://snehit.dev 2021-09-07T00:00:00+00:00 2021-09-07T00:00:00+00:00 https://snehit.dev/posts/love-alexa/ <p>Sometimes it feels shady to me that all popular voice assistant softwares are female. Google Assistant, Cortana and Alexa. Jarvis was supposed to happen, but it didn't. Samsung's Bixby wasn't making waves and then Samantha happened. <em>cough</em> better not talk about her <em>cough</em></p> <span id="continue-reading"></span> <p>What I see is that the voice assistant sector is 100% dominated by women. I know they are under represented in the IT industry overall, but the voice assistant industry kinda balances it out.</p> <p>These ladies are supposed to exist in your homes (along with any other lady). These can dim the lights, play songs and crack (poor) jokes - and then themselves do a "Ha Ha Ha". <em>Can your lady do that, mon ami?</em> She'd rather throw a tantrum because you've grown used to ordering around while slouching and binge watching some garbage web series which wouldn't even have seen the light of the day had there not been these OTT platforms accepting shitty content...</p> <p>Anyways, back to topic. These devices, apart from (of course) spying on your, are also intended to make you lazy, dependent and used to scary tech you don't actually need. God knows what the Kohler's engineers were thinking when they launched a commode with Alexa built in. Do you really need a female voice originating from <em>there</em>?</p> <p>Who ever imagined that 21st century boys will be considered cool because they keep a wiretap device in their rooms, which runs proprietary closed source software so you can never be 100% sure what all they are recording. Five years back, I had imagined the future people to be more tech literate and more aware of their digital rights. Unfortunately, the only statistics that have gone up are our stupidity and our reliance on big tech companies. Thanks to affordable high speed internet, we could've worked towards federalization and decentralization of web services. Rather, we are still wasting all our bandwidth transferring bytes from servers owned by big tech corporations.</p> <p>What's next? We recently got to know that some Amazon Echo devices had been coming equipped with low frequency transmitting devices. And now they come up with what they call <em>Sidewalk</em>. I'd rather call it Amazon Skynet.</p> <p>Blind trust might work in love; not with proprietary software. But wait... who do you love?</p> City Pop Rabbit Hole Diary Snehit Sah [email protected] http://snehit.dev 2021-08-31T00:00:00+00:00 2021-08-31T00:00:00+00:00 https://snehit.dev/posts/music/city-pop-rabbit-hole/ <p><em>Part 1 of a series idk how long it will be</em></p> <blockquote> <p>You didn't click on this video. All the choices you ever made led you here...</p> </blockquote> <p>I won't deny the fact. Back in July 2020, YouTube started showing me a suggestion video titled "Mariya Takeuchi Plastic Love". On the thumbnail was a black and white picture of a Japanese lady. I tried to avoid tapping on that video. YouTube only became more agressive with its suggestion. No matter what king of video I watched, tech, art, EDM or whatever, the first suggestion had to be this song called Plastic Love. Finally, after 3 weeks of dodging the suggestion, I ended up watching the video. Thus I had my first touch with...</p> <span id="continue-reading"></span><h2 id="gateway-drugs-of-city-pop">Gateway Drugs of City Pop</h2> <p>Plastic Love starts like a genuinely old song. There is said to be a 15 second rule on YouTube. If your video cannot hook the viewer in first 15 seconds, they will probably not watch rest of the video. Fortunately, the instruments soon turned to a groovy guitar melody and drums. The songs was from 1984, yet the drums felt quite modern. Is it City Pop? Sounded more like J-Pop. Even if it was a scam to lure innocent kids into City Pop, I'd say its a good thing :)</p> <div > <iframe width="560" height="315" src="https://www.youtube.com/embed/9Gj47G2e1Jc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div> <p>She starts singing, <em>Totsuzen no kisu ya atsui manazashi de</em>, and I know I have lost the battle. YouTube had finally reached the level where it could suggest songs that even I didn't know I wanted to listen.</p> <p>I soon discovered that I wasn't the first person to have fallen into the trap. There were <em>way too many</em> people like me. That black and white photo has become the face of City Pop in some sorts. And talking about gateway drugs, there is another song that happens to have dragged many people in here</p> <div > <iframe width="560" height="315" src="https://www.youtube.com/embed/nuU2YHtxMik" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div> <p>Stay With Me by Miki Matsubara. The song totally drags you into the emotion with no mercy.</p> <p>Thanks to the fact that these two are often the songs with which people start their City Pop journey, there are many covers of these tracks.</p> <h2 id="beyond-the-starters">Beyond the Starters</h2> <p>Once you watch one of the above videos, YouTube directs a storm of City Pop videos on to your home feed. Old Coca Cola advertisements, mundane shots from Japan, some random Japanese lady on an outing - the visuals often have no actual relations with the songs themselves. Yet, some mental imagery has become synonymous with City Pop. <em>Imagine yourself driving down the Tokyo roads in a Toyota, with City Pop tracks blasting from the speakers...</em>. You cannot escape the imagery once you have fallen in the rabbit hole.</p> <h3 id="junko-ohashi">Junko Ohashi</h3> <div > <iframe width="560" height="315" src="https://www.youtube.com/embed/nuU2YHtxMik" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div> <p>This was the first City Pop track to actually make me pause what I'm doing and take a moment to enjoy the imagery it built up in my head. The intro coupled with the album cover instantly dropped me in 80's New York. The overflowing modernity from a song almost four decades old - I couldn't resist.</p> <p>Being surrounded by skyscrapers, seeing men with a businesslike look, cars going down the road. I could feel myself walking past the long gone World Trade Center and experiencing the aura - something eastern world only saw in pictures. No wonder this track could very well be counted as remains from the Twin Towers. (note that the only reference to WTC is the cover album!)</p> <p>Judging by the title, the lyrics were supposed to elicit romance or something. Rather, they managed to give a different view of the fast paced dynamic life of a city as "modern" as New York(!?). (Don't blame me; reading experiences, it seems like New York, and especially the Twin Towers were symbols of "modernity" and "urbanisation")</p> <p>The song starts with this line</p> <blockquote> <p>にぎやかな劇場 ざわめくロビー (A bustling theatre, a noisy lobby)</p> </blockquote> <p>Perfect setting for a track that (inadvertently?) is a connection with 80's urban scenery. Its not like your usual tracks. Imagine, visiting a mall, and outside an eatery, you see your past love waiting for someone else. That's what this song is!</p> <p>There's another one - Sweet Love.</p> <div > <iframe width="560" height="315" src="https://www.youtube.com/embed/6C4VR81GDtM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div><h3 id="tomoko-aran">Tomoko Aran</h3> <p>There's no way you can skip her when discussing City Pop. <em>I'm In Love</em> is a classic that will never die.</p> <div > <iframe width="560" height="315" src="https://www.youtube.com/embed/pE2D3LWADFg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div> <p>Midnight Pretenders is another of my favorites.</p> <div > <iframe width="560" height="315" src="https://www.youtube.com/embed/KZyS-ms6-RA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div> <p>Again, you can talk about the album art. Why the hell does it look so cool? No idea.</p> <h3 id="anri">Anri</h3> <p>Golden voice definitely! She's an artist whose albums I can play start to end, without complains. Here are some</p> <div > <iframe width="560" height="315" src="https://www.youtube.com/embed/fp2psphgAK4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div><div > <iframe width="560" height="315" src="https://www.youtube.com/embed/L4AnjfSUJvg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div><div > <iframe width="560" height="315" src="https://www.youtube.com/embed/_cPJHqMBR7M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div><h3 id="junko-yagami">Junko Yagami</h3> <p>Who hasn't listened Bay City?</p> <div > <iframe width="560" height="315" src="https://www.youtube.com/embed/aQGvlemqUpE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div><h2 id="bonus-momoko-kikuchi">Bonus : Momoko Kikuchi</h2> <p>I was supposed to mention her in the next part. But <em>Glass no Sogen</em> is a must listen. How do you describe it? Angel voice? Heaven Harp?</p> <div > <iframe width="560" height="315" src="https://www.youtube.com/embed/GuhkGqJW5ZE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div> <p>Bye bye until part 2 where I'll list some more tracks you might not discover easily on your own.</p> Ethical to Sell Organs for Electronics? Snehit Sah [email protected] http://snehit.dev 2021-08-13T00:00:00+00:00 2021-08-13T00:00:00+00:00 https://snehit.dev/posts/ethical-to-sell-kidney-for-electronics/ <p>Forget the title. I see kids wasting their hearts, and grown up men wasting their kidneys. So, I don't care...</p> <span id="continue-reading"></span> <p>Anyways, the bigger question is that <em>is it ethical to purchase products from companies that have pending accusations of employing forced slave labour and child labour in their manufacturing units?</em></p> <p>Doesn't seem so. Because ironically, products marketed by such companies right now seem to be counted as <em>luxury</em> and <em>premium</em> products. Imagine, the phone you use to compose elaborate food porn for Instagram stories, was assembled by a person who never had enough to eat.</p> <p>Fortunately, this is not an issue to worry about. The situation won't get any worse. They are already using slave labour. What's next? <em>Indentured labour?</em> I don't see that making a come back anytime soon.</p> <p>Capitalism has been the buzzword among the upper few. With internet access being more universal, the idea has permeated down below too. Capitalism still heavily realies on addictive consumerism. And for addictive consumerism to sustain mentally, consumers must be kept away from facts that may push them away from purchasing goods.</p> <p>So we might be just waiting to see more such practices evolve. But as I said, don't worry because indentured labour isn't making a come back.</p> Use of Unethical Software in Education Sector Snehit Sah [email protected] http://snehit.dev 2021-07-21T00:00:00+00:00 2021-07-21T00:00:00+00:00 https://snehit.dev/posts/foss/unethical-software-in-education/ <h2 id="introduction">Introduction</h2> <p>Online education has received a huge boost during the pandemic. Even before the pandemic, many educational institutes were focussing on tech literacy. However, all this ends up promoting unethical software. During the IT boom in past decades, we have seen many corporations rely on selling software to make money. Oftentimes, this software is proprietary and robs users of their basic rights and freedoms. With the recent push towards IT education and increasing reliance on software in the education industry, unethical softwares have amassed a humongous user base. I'll try to justify my basis of calling certain softwares "unethical" and how educational institutes unknowingly end up promoting them. The issue has a heavy impact on the quality of software general users eventually have to bear with.</p> <span id="continue-reading"></span><h2 id="why-foss">Why FOSS?</h2> <p>Free (as in 'freedom') software today is the backbone of many software enterprises. Modern app development is increasingly growing reliant on code reuse. This is made possible because the source code is under an open-source license that lets users adapt, edit and redistribute it.</p> <p>FOSS encourages choice and power on the part of the user. They are not bound to an ecosystem or suite and rather are free to mix and match the software they like and use it. More advanced users also benefit by being able to modify the software and adapt it to their needs. Having the right to reverse engineer software allows students to learn and possibly develop solutions to existing problems without requiring to code everything from scratch, or relying on an opaque library.</p> <p>Even for a normal person, who isn't necessarily into programming, FOSS plays a vital role in their lives. Most of our tech services are online nowadays. And the server space is dominated by free and open-source operating systems, making it possible for you to access the various services on the internet.</p> <p>FOSS are almost always privacy-respecting and are audited by independent users, who will be quick to point out any flaw that remotely affects privacy. This auditing by independent users also means that FOSS gets faster bug fixes and can be more secure. It may even provide better performance or success rate than its proprietary counterparts. While there is no evidence to conclusively prove this claim, it is a fact that the security by obscurity model followed by most proprietary software hasn't made them any more secure or reliable than FOSS.</p> <h2 id="ethics">Ethics</h2> <p>By encouraging users to modify and redistribute the software, FOSS inculcates a sense of responsibility and respect for freedom. This becomes very important in an age where people gladly agree to give up their privacy and rights <em>just</em> to be "connected" on so-called "social media" platforms.</p> <p>Closed source and proprietary softwares do not share their source code so adapting it to your needs is impossible unless you are happy with the exact software that is shipped. They can also not be reverse-engineered for learning purposes or otherwise. Developers will try their best to obfuscate the code so that reverse-engineering becomes futile. It means that as a user, you can never be sure that the software is not doing anything malicious. We have seen cases in the past where manufacturers slow down old phones so that people buy new ones or social media apps collecting tons of private user data. There are many such examples of unethical practices, which are made possible because of closed source software.</p> <h2 id="the-education-sector">The Education Sector</h2> <p>With the advent of digital learning, students have to use a variety of softwares to complete their courses. At the very least, they need to use a communication platform and video call software.</p> <p>With Google and Microsoft supporting easy onboarding for educational institutes, there is a high probability that a school/college is using services from one of these companies.</p> <p>Their software is closed source and proprietary, which means the students have no idea whatsoever about the processing of their data. Meeting softwares may record videos and audio without explicit permission and use it to train their AI software. Misuse of this data is very much possible (and it was highlighted in the case where Amazon employees were caught listening to users via Alexa). Companies try to get around legal hurdles by including clauses in their Terms of Use, which students have to accept if they want to attend classes.</p> <p>Now, this is a grave situation - as bad as the teacher asking students to do a socially unacceptable act if they want to pass the semester. It will surely become news if something like that happens outside of the tech domain. But when the same student is forced to give up his privacy in the hands of a big tech corporation, so that he can pass the semester, nobody bats an eyelid. Forcing students - directly or indirectly - to use proprietary software should be considered a severe violation of their rights.</p> <p>Take another common example. In the current age of digital education, many times students are supposed to prepare a "Word Document" or a "PowerPoint Presentation" for their assessment. These again are do or die situations for the student. Either they use a closed source proprietary software (MS Office) or they fail the class. Instead, the teacher should accept assignments in a format like PDF, which can be created using any software the student may want to use. If it's necessary to accept assignments in a document or presentation format, then teachers can encourage the use of FOSS alternatives for MS Office, like Libre Office.</p> <p>There are numerous other softwares students are forced to use - like online forms for examinations, circuit simulation softwares etc.</p> <p>Richard Stallman, who started the free software movement, believes that making students use proprietary software is like making them addicted to cigarettes. Eventually, proprietary softwares will get hold of the student's life and she/he will have great difficulty in untangling themselves from this addiction. It is the moral responsibility of educational institutes to educate students about these issues and encourage them to stay away from such addictions.</p> <p>The lack of awareness about FOSS among teachers is eventually inherited by students. These students, later in their lives make bad choices for the softwares to use because they could never appreciate FOSS. A person who grew up in a dictatorial country, cut off from the world, will probably never think of democracy.</p> <h2 id="future-concerns">Future Concerns</h2> <p>We already know that the nature of FOSS ensures slightly higher levels of quality than their proprietary counterparts in most cases. It might seem that the difference in success rates of two softwares doesn't matter if it is something as low as 0.001%. But, every fraction matters when it's about life and death.</p> <p>Consider the Boeing MAX 737, which made headlines after 346 people died in two crashes. The cause was traced back to a software that Boeing had installed in the flight control system. Flight crashes are not at all common, and this case can certainly be considered an exception. But lives were lost, which cannot be ignored. We need to think - could we have done better? Had the software been open source, it is possible that someone on the internet would have pointed out the issue beforehand and the deaths could have been avoided.</p> <p>The field of medical science uses digital equipment nowadays, whose softwares demand very high precision and success rates. After all, the goal is to save people and we cannot afford to lose lives just because a piece of software was at fault. Consider the example of pacemakers, which assist the heart to maintain a constant rhythm. If the software of a pacemaker suffers from any fault, it will pose a huge risk to the patient. Truth is that many doctors don't know how reliable the software is. If manufacturers make their pacemaker software open source then independent developers from around the world can audit it and there is a higher chance of critical issues being fixed before a patient ends up losing her/his life. Karen Sandlers, who has worked extensively to develop and improve FOSS, gave a keynote in 2018 where she highlighted this issue and described six years of her failed attempts at acquiring source code for her pacemaker. The keynote can be watched on YouTube <a href="https://www.youtube.com/watch?v=8wPAHu_zYDw">at this link</a>.</p> <p>With the growing reliance on complex closed source softwares everywhere - like driver assist in cars, autopilot systems, medical equipment etc, we can only wonder how much risk our lives are at.</p> <h2 id="conclusion">Conclusion</h2> <p>The change must begin from the education sector. This is where students acquire new ideas and form opinions. If we promote the usage of FOSS, the next generation will benefit in many ways. Reliance on proprietary software will only help big tech corporations develop monopolies and follow unethical practices without anyone criticizing them.</p> Generating Combinations using C++ Snehit Sah [email protected] http://snehit.dev 2021-07-21T00:00:00+00:00 2021-07-21T00:00:00+00:00 https://snehit.dev/posts/programming/generating-combinations-cpp/ <h2 id="introduction">Introduction</h2> <p>The task for this post is to help you understand how to generate combinations of size <code>r</code> using numbers from 1 to <code>n</code> and then extend that code to generate combinations for any set of objects.</p> <span id="continue-reading"></span> <p>When I say <code>n = 5</code> and <code>r = 3</code>, it means we are dealing with the first five natural numbers to generate combinations of size 3.</p> <h2 id="understanding-combinations">Understanding Combinations</h2> <p>We shall be generating combinations in lexicographic order. Also, since combination does not concern itself with the relative order the chosen elements are arranged in, we shall always be having our chosen elements in lexicographical order too.</p> <p>The first combination we choose has to be the first <code>r</code> elements when the <code>n</code> objects are sorted. This is because it gives us the lexicographically smallest word with the individual elements themselves in lexicographical order too. (basically, the if all combinations were arranged in a dictionary, then we want to start with the first one) So, in case of <code>n = 5</code> and <code>r = 3</code>, the first combination is <code>123</code>.</p> <p>Now, think what should be the last combination. I propose that it will be the last <code>r</code> elements when the <code>n</code> objects are sorted. Why should it be? When we are generating combinations in lexicographical order, each combination should have a greater position in a dictionary. So the last combination should have the greatest elements from given objects. The chosen elements themselves should also be in lexicographical order.</p> <p>The knowledge of last combination also gives us an interesting observation. The maximum value at a given index <code>idx</code> can be <code>n - r + idx + 1</code>, where index starts from zero. This is necessary to maintain the dictionary order of individual elements in a combination.</p> <p>Take for example the case of <code>n = 5</code> and <code>r = 3</code>. If we position the number 5 at index 1, then the combination will look like <code>X5_</code>, where <code>X</code> may be any number lower than 5. The blank at third position should have a number greater than 5 if we are to maintain dictionary order. But placing 6 there is not possible since we only have 5 elements. According to the formula <code>n - r + idx + 1</code>, the maximum value at third position (or second index) can be 4.</p> <p>Another thing to note is that every time we increment a position, we need to set the elements to its right as one more than its left neighbor. This will be clear when I discuss the code.</p> <h2 id="formal-algorithm">Formal Algorithm</h2> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>fun next_combination : </span><span> parameters: integer n - max objects available </span><span> integer r - size of chosen set </span><span> array curr_comb - denoting </span><span> current combination of r elements </span><span> integer idx - index to increment </span><span> </span><span> return: true if next combination exists </span><span> curr_comb is updated in place </span><span> with the next combination </span><span> false if last combination is provided </span><span> ____ </span><span> </span><span> if idx &lt; 0 : </span><span> return false </span><span> </span><span> if curr_comb[idx] &lt; n - r + idx + 1 : </span><span> ++curr_comb[idx] </span><span> for i in (idx + 1, n - 1): </span><span> curr_comb[i] = curr_comb[i - 1] </span><span> return true </span><span> </span><span> else : </span><span> return next_combinaition(n, r, curr_comb, idx - 1) </span></code></pre> <p>For this function to work, it should be called with <code>idx</code> as <code>r - 1</code>, since we want to start incrementing from last index. This code first check if the index to increment is less than 0. If yes, it means that the next combination does not exist, or in other words, we are already at last combination.</p> <p>Then it checks if the value at <code>curr_comb[idx]</code> is less than its maximum permissible value. If yes, then it increments the value at <code>idx</code> and sets its following elements as one plus their left neighbor.</p> <p>If the value it <code>idx</code> is already the maximum allowed, then the function recursively calls itself with same parameters, but <code>idx</code> decremented by one. This continues till either the next combination is found, or the function is called with <code>idx</code> less than zero, in that case next combination does not exist.</p> <p>The function is recursive, so it must pass the sanity test. Does it stop recursing at some point? Each recursive call decrements <code>idx</code> by 1. Eventually, <code>idx</code> will be less than zero, in which case the function will no longer recurse. So, it is guaranteed that the function does not recurse indefinitely.</p> <h2 id="c-code">C++ Code</h2> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#b48ead;">void </span><span style="color:#8fa1b3;">increment_neighbor</span><span>(std::vector&lt;</span><span style="color:#b48ead;">int</span><span>&gt; &amp;</span><span style="color:#bf616a;">arr</span><span>, </span><span style="color:#b48ead;">int </span><span style="color:#bf616a;">idx</span><span>) </span><span>{ </span><span> </span><span> </span><span style="color:#b48ead;">for </span><span>(</span><span style="color:#b48ead;">int</span><span> i = idx; i &lt; arr.</span><span style="color:#bf616a;">size</span><span>(); ++i) </span><span> arr.</span><span style="color:#bf616a;">at</span><span>(i) = arr.</span><span style="color:#bf616a;">at</span><span>(i - </span><span style="color:#d08770;">1</span><span>) + </span><span style="color:#d08770;">1</span><span>; </span><span>} </span><span> </span><span style="color:#b48ead;">bool </span><span style="color:#8fa1b3;">_next_combination</span><span>(</span><span style="color:#b48ead;">int </span><span style="color:#bf616a;">n</span><span>, </span><span style="color:#b48ead;">int </span><span style="color:#bf616a;">r</span><span>, std::vector&lt;</span><span style="color:#b48ead;">int</span><span>&gt; &amp;</span><span style="color:#bf616a;">curr_comb</span><span>, </span><span> </span><span style="color:#b48ead;">int </span><span style="color:#bf616a;">idx</span><span>) </span><span>{ </span><span> </span><span> </span><span style="color:#b48ead;">if </span><span>(idx &lt; </span><span style="color:#d08770;">0</span><span>) </span><span> </span><span style="color:#b48ead;">return </span><span style="color:#d08770;">false</span><span>; </span><span> </span><span> </span><span style="color:#b48ead;">if </span><span>(curr_comb.</span><span style="color:#bf616a;">at</span><span>(idx) &lt; n - r + idx + </span><span style="color:#d08770;">1</span><span>) { </span><span> ++curr_comb.</span><span style="color:#bf616a;">at</span><span>(idx); </span><span> </span><span style="color:#bf616a;">increment_neighbor</span><span>(curr_comb, idx + </span><span style="color:#d08770;">1</span><span>); </span><span> </span><span style="color:#b48ead;">return </span><span style="color:#d08770;">true</span><span>; </span><span> } </span><span> </span><span style="color:#b48ead;">else </span><span> </span><span style="color:#b48ead;">return </span><span style="color:#bf616a;">_next_combination</span><span>(n, r, curr_comb, idx - </span><span style="color:#d08770;">1</span><span>); </span><span>} </span><span> </span><span style="color:#b48ead;">bool </span><span style="color:#8fa1b3;">next_combination</span><span>(</span><span style="color:#b48ead;">int </span><span style="color:#bf616a;">n</span><span>, </span><span style="color:#b48ead;">int </span><span style="color:#bf616a;">r</span><span>, std::vector&lt;</span><span style="color:#b48ead;">int</span><span>&gt; &amp;</span><span style="color:#bf616a;">curr_comb</span><span>) </span><span>{ </span><span> </span><span> </span><span style="color:#b48ead;">return </span><span style="color:#bf616a;">_next_combination</span><span>(n, r, curr_comb, r - </span><span style="color:#d08770;">1</span><span>); </span><span>} </span></code></pre> <p>Following are the required includes:</p> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#b48ead;">#include </span><span>&lt;</span><span style="color:#a3be8c;">algorithm</span><span>&gt; </span><span style="color:#b48ead;">#include </span><span>&lt;</span><span style="color:#a3be8c;">utility</span><span>&gt; </span><span style="color:#b48ead;">#include </span><span>&lt;</span><span style="color:#a3be8c;">vector</span><span>&gt; </span></code></pre> <p>This code is a direct implementation of the algorithm I shared above. The part that increments the neighbors by 1 has been extracted to its own function called <code>increment_neighbor</code>.</p> <p>You might ask, why are there two functions named <code>next_combination</code>, one with a preceding underscore. The goal of a good interface is to be as simple as possible. In the recursive function, we initially call it with <code>idx = r - 1</code>. For a programmer reusing our function, it may be tedious to pass the fourth parameter, when it can be simply deduced from the third second one.</p> <p>So, we create a helper function that takes the three required parameters and calls the original recursive function with fourth parameter set.</p> <h2 id="using-our-function">Using Our Function</h2> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span style="color:#b48ead;">int </span><span style="color:#8fa1b3;">main</span><span>() </span><span>{ </span><span> </span><span> </span><span style="color:#b48ead;">int</span><span> n = </span><span style="color:#d08770;">0</span><span>, r = </span><span style="color:#d08770;">0</span><span>; </span><span> </span><span> </span><span style="color:#65737e;">// take input for n and r </span><span> </span><span> std::cout &lt;&lt; &quot;</span><span style="color:#a3be8c;">Enter r individual elements (integers) of</span><span>&quot; </span><span> &quot;</span><span style="color:#a3be8c;"> current combination separated by spaces</span><span style="color:#96b5b4;">\n</span><span>&quot;; </span><span> </span><span> std::vector&lt;</span><span style="color:#b48ead;">int</span><span>&gt; </span><span style="color:#bf616a;">numbers</span><span>(r); </span><span> </span><span> </span><span style="color:#b48ead;">for </span><span>(</span><span style="color:#b48ead;">int</span><span> i = </span><span style="color:#d08770;">0</span><span>; i &lt; r; ++i) </span><span> std::cin &gt;&gt; numbers.</span><span style="color:#bf616a;">at</span><span>(i); </span><span> </span><span> </span><span style="color:#b48ead;">if </span><span>(</span><span style="color:#bf616a;">next_combination</span><span>(n, r, numbers)) { </span><span> std::cout &lt;&lt; &quot;</span><span style="color:#a3be8c;">Next combination is</span><span style="color:#96b5b4;">\n</span><span>&quot;; </span><span> </span><span style="color:#b48ead;">for </span><span>(</span><span style="color:#b48ead;">auto</span><span> x : numbers) </span><span> std::cout &lt;&lt; x &lt;&lt; &quot; &quot;; </span><span> std::cout &lt;&lt; &quot;</span><span style="color:#96b5b4;">\n</span><span>&quot;; </span><span> } </span><span> </span><span style="color:#b48ead;">else </span><span>{ </span><span> std::cout &lt;&lt; &quot;</span><span style="color:#a3be8c;">The input is already the final combination</span><span style="color:#96b5b4;">\n</span><span>&quot;; </span><span> } </span><span> </span><span> </span><span style="color:#b48ead;">return </span><span style="color:#d08770;">0</span><span>; </span><span>} </span></code></pre> <p>This code will simply check if <code>next_combination</code> return true or false. If true, it means that the next combination was found and it is printed. Otherwise, inform user that we are already at last combination.</p> <p>To generate all combination, use the following snippet.</p> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span>std::vector&lt;</span><span style="color:#b48ead;">int</span><span>&gt; </span><span style="color:#8fa1b3;">numbers</span><span>(</span><span style="color:#bf616a;">r</span><span>); </span><span> </span><span style="color:#b48ead;">for </span><span>(</span><span style="color:#b48ead;">int</span><span> i = </span><span style="color:#d08770;">1</span><span>; i &lt;= n; ++i) </span><span> numbers.</span><span style="color:#bf616a;">at</span><span>(i) = i; </span><span> </span><span style="color:#b48ead;">do </span><span>{ </span><span> </span><span style="color:#b48ead;">for </span><span>(</span><span style="color:#b48ead;">auto</span><span> x : numbers) </span><span> std::cout &lt;&lt; x &lt;&lt; &quot; &quot;; </span><span> std::cout &lt;&lt; &quot;</span><span style="color:#96b5b4;">\n</span><span>&quot;; </span><span>} </span><span style="color:#b48ead;">while </span><span>(</span><span style="color:#bf616a;">next_combination</span><span>(n, r, numbers)); </span></code></pre> <h2 id="running-on-custom-elements">Running on Custom Elements</h2> <p>Lets say the user does not want to generate combination of numbers, but instead wants to generate combinations of a custom set of objects. The object can be anything - character, string, struct etc.</p> <p>The basic idea is to store the <code>n</code> individual elements in an array. Generate the combination on numbers from 1 to <code>n</code> as we did earlier. But while printing the combination, instead of number, print the element at that position.</p> <p>As an example, here is the snippet for generating combinations of words.</p> <pre data-lang="cpp" style="background-color:#2b303b;color:#c0c5ce;" class="language-cpp "><code class="language-cpp" data-lang="cpp"><span>std::vector&lt;</span><span style="color:#b48ead;">int</span><span>&gt; </span><span style="color:#8fa1b3;">numbers</span><span>(</span><span style="color:#bf616a;">r</span><span>); </span><span>std::vector&lt;</span><span style="color:#b48ead;">int</span><span>&gt; </span><span style="color:#8fa1b3;">words</span><span>(</span><span style="color:#bf616a;">r</span><span>); </span><span> </span><span style="color:#b48ead;">for </span><span>(</span><span style="color:#b48ead;">int</span><span> i = </span><span style="color:#d08770;">1</span><span>; i &lt;= n; ++i) </span><span> numbers.</span><span style="color:#bf616a;">at</span><span>(i) = i; </span><span> </span><span>std::cout &lt;&lt; &quot;</span><span style="color:#a3be8c;">Enter n individual elements (words)</span><span>&quot; </span><span> &quot;</span><span style="color:#a3be8c;"> separated by spaces</span><span style="color:#96b5b4;">\n</span><span>&quot;; </span><span> </span><span style="color:#b48ead;">for </span><span>(</span><span style="color:#b48ead;">int</span><span> i = </span><span style="color:#d08770;">0</span><span>; i &lt; n; ++i) </span><span> std::cin &gt;&gt; words.</span><span style="color:#bf616a;">at</span><span>(i); </span><span> </span><span style="color:#b48ead;">do </span><span>{ </span><span> </span><span style="color:#b48ead;">for </span><span>(</span><span style="color:#b48ead;">auto</span><span> x : numbers) </span><span> std::cout &lt;&lt; word.</span><span style="color:#bf616a;">at</span><span>(x) &lt;&lt; &quot; &quot;; </span><span> std::cout &lt;&lt; &quot;</span><span style="color:#96b5b4;">\n</span><span>&quot;; </span><span>} </span><span style="color:#b48ead;">while </span><span>(</span><span style="color:#bf616a;">next_combination</span><span>(n, r, numbers)); </span></code></pre> <h2 id="memoization">Memoization</h2> <p>Recursive algorithms can be made much faster when using memoization. Do we need memoization?</p> <p>Memoization helps when the function is called with the same parameters multiple times. By storing intermediate results, it does not need to do computations if the parameters provided are not new.</p> <p>In our function, <code>n</code> and <code>r</code> are constant throughout. <code>idx</code> changes its value, but it does so in a very small range. So there seems to be lot af scope for repetition of parameters. However, the parameter <code>curr_comb</code> does not repeat. Each combination is different. When recursing with the same combination, then the value of <code>idx</code> is guaranteed to change.</p> <p>So we need not use memoization, as the intermediate values are never reused.</p> <h2 id="conclusion">Conclusion</h2> <p>That was the end of this post. Hope you learned something new. You can always shoot me feedback on my email, which is visible on my GitHub profile once you log in.</p> Fastly CDN Outage Snehit Sah [email protected] http://snehit.dev 2021-06-11T00:00:00+00:00 2021-06-11T00:00:00+00:00 https://snehit.dev/posts/fastly-outage/ <p>June 8 - I deployed a simple webpage on GitHub pages. I shared it on a forum where users will take interest in the site. Very soon, a user shared a screenshot saying that the website was inaccessible. At first I was confused as to why this happened. My site was a simple one page HTML site. No external dependencies or sources (not even fonts).</p> <span id="continue-reading"></span> <p>I quickly tried accessing my webpage and found that indeed my site was giving a 503. I looked up if GitHub was down. This led me to a tweet by GitHub where they acknowledged that their services were experiencing problems. Users started reporting that fetching assets from GitHub resulted in errors. Among many other things, this affected installation process of Linux-based distros which relied on GitHub to host repositories, like ArchCraft.</p> <p>That afternoon I couldn't access Reddit. Their services were down too. It seemed strange that two big websites were experiencing issues at the same time. Reading up on news sites, I found that Fastly CDN was facing an outage that led to many other services being down too - Twitch, Amazon, Spotify, HBO Max, Quora, PayPal, Vimeo, the New York Times, BBC, Financial Times etc.</p> <p>Good news is that the outage was not a result of malicious intentions of a hacker. Services started being restored within 8 hours.</p> <p>CDN outages can mean significant inconvenience. Smaller websites don't need to rely on CDN. These are of prime interest to those services that expect huge traffic and it will be virtually impossible for a single server to handle all the requests. CDN help in this situation by distributing load across different servers around the world. When CDNs go down, they defeat their purpose. However such outages don't happen every now and then. Usually a specific region faces outage and the traffic in that region is redirected to a different region. This way, the global network of CDN ensure that outage at a particular server location doesn't affect services. This time unfortunately, this was a global outage where majority regions were affected.</p> Foss and Profit Snehit Sah [email protected] http://snehit.dev 2021-06-07T00:00:00+00:00 2021-06-07T00:00:00+00:00 https://snehit.dev/posts/foss/foss-and-profit/ <p>Often, when people think of FOSS (Free and Open Source Software), they don't consider that it can bring monetary benefits. It is a prevailing myth that open source software is not compatible with a successful business model. This is part of the reason why open source tends to remain a hobby for most people and never develops into a "profession".</p> <span id="continue-reading"></span><h2 id="a-small-talk-on-foss">A Small Talk on FOSS</h2> <p>The core of this misunderstanding is the word "Free". FOSS need not be free of cost. "Free" refers to the software giving users certain rights and freedoms. I'll borrow text for the four essential freedoms from the <a href="https://www.gnu.org/philosophy/free-sw.en.html">GNU website</a>.</p> <ul> <li>The freedom to run the program as you wish, for any purpose (freedom 0).</li> <li>The freedom to study how the program works, and change it so it does your computing as you wish (freedom 1). Access to the source code is a precondition for this.</li> <li>The freedom to redistribute copies so you can help others (freedom 2).</li> <li>The freedom to distribute copies of your modified versions to others (freedom 3). By doing this you can give the whole community a chance to benefit from your changes. Access to the source code is a precondition for this.</li> </ul> <p>These never mention that the program needs to be provided free of cost to users. Software that is free of cost is better referred to as "gratis", which does not contain any ambiguity as to the word "free". Often, FOSS users or devs will refer to "free" as "libre" to avoid misunderstanding.</p> <h2 id="why-will-users-pay-for-code-that-is-open-source">Why will users pay for code that is open source?</h2> <p>You are not selling your code. You are selling a product, that is not your code. What can you sell? A compiled binary of your code, or hassle-free deployment services for your application. You can sell server services for your application. Users will pay for the service you provide. I'll list some examples that I like.</p> <ul> <li>Threema is an instant messenger like WhatsApp, that is built around security and privacy. All their tools are open source and can be freely accessed on GitHub. They offer their application for a one time charge of approx 4.5USD. They also have communication solutions for businesses and educational institutes. Their licence for educational institutes costs 10.10USD, which is quite affordable considering that it's a lifetime license. If you want, you can also self-host Threema on your server using Nginx.</li> <li>Ardour is a professional digital audio workstation. The developers constantly push out new features and they have an active community. Their code is open source, however, the binary can be aquired on a pay what you want model.<sup>1</sup> You can get all features at as low as 1USD per month. The project also accepts donations to fund itself.</li> <li>FastHub is a feature-packed unofficial GitHub client for Android. A basic version of the app is free to download. For extra features and themes, you need to pay a one time charge for a license. These license charges keep the project running. If you want, you can manually build the app from source.</li> <li>Matrix is a Discord like communication, but the protocol is open source and federated. It is an open standard for interoperable, decentralised, real-time communication over IP. The application is free to deploy on your VPS or elsewhere. The creators of Matrix provide a Matrix hosting service called Element that helps them fund the project.</li> <li>Linux is certainly the software that has maximum influence on the services we use. It powers most of the servers and many supercomputers. The Linux Foundation offers courses, among which the advanced ones are paid.</li> </ul> <p>You can find many more examples where open source software helps earn money. As you saw, this profit need not necessarily come from selling the software itself. You can sell services that are built around your software.</p> <h2 id="market-competition">Market Competition</h2> <p>One insecurity around open sourcing software that often comes up is the possible competition you face from forks. Take the example of FastHub I listed above. A user forked that repository and created a version with all pro features enabled by default. He then posted it on F-Droid. The upstream developer was not happy with that move.</p> <p>Your open-source application faces a constant threat from forks. These forks may not be as simple as just enabling some locked settings. Forks can add new features and create their own identity. Since the code is open to all, you need to create your identity around the services you provide. Large open source organizations often have good support channels for customers that help them stay in demand.</p> <h2 id="is-it-viable">Is it viable?</h2> <p>Both yes and no. This depends on the scale of your application and the number of users. Do you receive enough donations? Do your services get enough users?</p> <p>A new project does not start generating revenue from day one. You keep working on it, and somewhere down the line, you get contributors and happy users who willingly donate to keep your project alive. When you feel you have enough users, you can think about making that initial investment to launch your paid services around your software.</p> <h2 id="conclusion">Conclusion</h2> <p>Selling FOSS or FOSS related services is a win-win for users and developers. Users will be paying for software that they trust and like. The developers can continue to develop ethical software and keep the community alive. The market will get aligned with ethics and that's in favour of all of us. Creating an atmosphere where users pay for FOSS can heavily incentivise ethical software.</p> <hr> 1. Since Ardour is open source, you will find binaries available in repositories of Linux distros. While that is available for free and it is totally legal to do so, it is recommended to donate to the project as a means of supporting development. Playing YouTube Videos with VLC/MPV Snehit Sah [email protected] http://snehit.dev 2021-06-01T00:00:00+00:00 2021-06-01T00:00:00+00:00 https://snehit.dev/posts/shell/playing-youtube-videos-with-mpv/ <p>Here's a quick tip - you can play YouTube videos from your terminal. I like YouTube because its home to lot of content that otherwise is difficult to find. For example, I get my fill of 80's City Pop from YouTube.</p> <span id="continue-reading"></span> <p>Now I'm not a fan of bloated websites. The YouTube video player page does lot more than just playing a video. It shows suggestions, comments and a bloated user interface.</p> <p>So, the easy way out is to use your own video player to play the video!</p> <p>Go to a terminal and run</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">mpv </span><span>&quot;</span><span style="color:#a3be8c;">https://www.youtube.com/watch?v=_cPJHqMBR7M</span><span>&quot; </span></code></pre> <p>This will stream the video in MPV. If you are more of a VLC person, you can use that too.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">vlc </span><span>&quot;</span><span style="color:#a3be8c;">https://www.youtube.com/watch?v=_cPJHqMBR7M</span><span>&quot; </span></code></pre> <p>To play only audio, you can pass <code>--no-video</code> flag while invoking mpv.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">mpv </span><span>&quot;</span><span style="color:#a3be8c;">https://www.youtube.com/watch?v=_cPJHqMBR7M</span><span>&quot;</span><span style="color:#bf616a;"> --no-video </span></code></pre> <p>You can play/pause with spacebar. Seek with arrow keys. Volume is controlled with number keys 9 and 0.</p> <p>The only problem with the above approach is that you still need to open the browser and bear along with the web interface to search for video and get those links. Well, there's a solution for that too!</p> <p>Mps-youtube is a command line utility that lets you search and play content from YouTube. You can install the application from your distro repositories or via pip. On Arch Linux, you need to install <code>mps-youtube-git</code> from AUR because the stable release from community repo does not work with mpv. If you want to use VLC as your player, then the <code>mps-youtube</code> package from community repo will work too. If you don't want to install via AUR, you can use pip to install the development version.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pip</span><span> install git+https://github.com/mps-youtube/mps-youtube.git </span></code></pre> <p>You can launch the application with <code>mpsyt</code> in your shell. Then you need to set your YouTube API keys which is a five minute task.</p> <p>In the application, I recommend running <code>set search_music false</code> because lot of songs are not recognized as music by YouTube. But it depends on the artists you usually listen. Then you can search in vim style! Press forward slash followed by your search term. It will present a list of results. Choose the one to play by entering the corresponding number.</p> <p>By default, it plays only audio. If you want to play videos too, you will need to run <code>show_video true</code> inside the application. If using a new version of mpv, I also recommend running <code>set player vlc</code> because I had issues with using mpv for video.</p> <p>Thats it for this post!</p> Switching to Programmer Dvorak - 3 Months Later Snehit Sah [email protected] http://snehit.dev 2021-05-24T00:00:00+00:00 2021-05-24T00:00:00+00:00 https://snehit.dev/posts/3-months-of-programmer-dvorak/ <p>I've been trying to learn touch typing for long. Like most people, I practiced on qwerty, but could never actually touch type with confidence.</p> <span id="continue-reading"></span> <p>First time I touch typed, I was in third grade. As a part of the computer club, I had to type out a children's book into MS Word and then copy paste the text into Windows Movie Maker to make a short video with the text and pictures. That ended up being my last touch with touch typing for ten years.</p> <h2 id="start-fresh">Start Fresh</h2> <p>In 2020, I decided to learn touch typing, no matter what! Easy thing to say, but after typing for ten years by looking at the keyboard, I couldn't get rid of that habit. Looking back, I felt this was an investment I was too lazy to do. During my school days, I learnt basic C++, did some competitive coding, did lot of HTML and CSS, typed many many documents and even got Microsoft Office Specialist Certification - all via hunting and pecking on the keyboard.</p> <p>Old habits are tough to change. I practiced on qwerty, and reached a tiny 40wpm.</p> <h2 id="switching-to-new-layout">Switching to new layout</h2> <p>A random user on a discord server suggested me to try out an alternative layout so that looking at the keyboard becomes futile. The idea resonated with me. Up until then, I never considered using an alternate layout.</p> <p>I looked up on the net, and found that Dvorak kinda fit my needs. Claimed to be comfortable. Common alphabets placed on the home row. And right hand has more movement than the left, which is good for right handed people like me.</p> <p>I started practicing on this website called <a href="https://learn.dvorak.nl/">learn.dvorak.nl</a>. The website does not require you to change your layout from system settings. Instead, the website remaps keys based on input from your qwerty input. Of course, you can disable that feature if you have changed to Dvorak from system settings.</p> <h2 id="enter-programmer-edition">Enter Programmer Edition</h2> <p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vgwn3x04y30m0bvw1hoe.png" alt="Programmer Dvorak Layout" /></p> <p>About two weeks later, I was comfortable typing on Dvorak keyboard. As they claimed, it was easy to learn. I wasn't a fast typer by any measure, but at least the keys were memorized and I could type without looking at the keyboard - even if it was at 15wpm. I decided I was ready to switch to Dvorak full time.</p> <p>I went to the Arch Wiki to know how to change my layout. There I found another Dvorak based layout - Programmer Dvorak. The idea behind this layout was to place the common symbols used in programming on the top number row, and have them inserted without pressing Shift. The numbers need to be inserted with Shift key combination. Alphabets were in their right locations as they are on Simplified Dvorak.</p> <p>This layout, for obvious reasons, immediately appealed to me. I started using it right away.</p> <h2 id="experience">Experience</h2> <p>I get the typing benefits of Dvorak, which are great by the way. I feel less hand movement as compared to my Qwerty touch typing sessions. Layout makes sense, although I am not a fan of positioning the letter <code>l</code> where it is.</p> <p>The layout is comfortable too. My wrists don't curse me anymore when I am typing for long hours.</p> <p>Having symbols on the top row makes them easily accessible. I am surprised by the fact that I am now happily typing out symbols while coding without requiring to press Shift.</p> <h2 id="bottom-line">Bottom line</h2> <p>Simplified Dvorak is good for all practical purposes. Programmer Dvorak comes with a small problem that the numbers on top row are not in increasing order. Typing numbers has been a severe pain for me, and those who watched me live stream my code often asked me why I was typing wrong whenever I had to type a number.</p> <p>I faced another crisis when I gave my programming test at university. They had Windows computer, and I wasn't allowed to use my laptop to give the test. Dvorak is a universal layout which you will find on all modern operating systems. However, Programmer Dvorak is not universal, meaning I did not have that for my exam. Alphabets were easy to type, but typing symbols - which you do after almost every word - was a serious pain. I suffered the torture for the first task and switched to Qwerty for my second task. Hunt and peck is more efficient than pressing random keys and hoping they are correct.</p> <h2 id="conclusion">Conclusion</h2> <p>If you are happy with your current layout, continue with it by all means. However, even if there's a tiny bit of curiosity in you to try out alternate layouts, then make sure you experiment.</p> <p>If you want to be able to type on any computer - in case you type on other's systems often - then Simplified Dvorak is the best option. If you want Dvorak but are mostly typing on your own system (like me) do consider Programmer Dvorak.</p> <p>If you don't mind using a non-universal layout, then there is Colemak layout, which looks quite impressive. Its easy to transition from Qwerty to Colemak. And reading up on their website, it certainly is worth trying.</p> <p>For me, I am happy with Programmer Dvorak and am going to continue with it.</p> Beginner's Guide To Shell Aliases With Examples Snehit Sah [email protected] http://snehit.dev 2021-05-24T00:00:00+00:00 2021-05-24T00:00:00+00:00 https://snehit.dev/posts/shell/beginners-guide-to-shell-aliases/ <h2 id="introduction">Introduction</h2> <p>*nix shell is a powerful tool that can help you go about your work easily. At the lowest level, it can be thought of as an interpreted language (like python). However, it can seamlessly run binaries and this power combined with shell grammar, you can write scripts to automate processes on your system.</p> <span id="continue-reading"></span> <p>Shell has this feature where you can define aliases to existing commands. So, if I alias <code>w</code> to <code>wget</code>, then every time I run <code>w</code>, it will be interpreted as <code>wget</code>.</p> <h2 id="defining-aliases">Defining Aliases</h2> <p>Shell aliases can be easily defined by the following syntax:</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">&lt;keyword&gt;</span><span>=&quot;</span><span style="color:#a3be8c;">some long command</span><span>&quot; </span></code></pre> <p>So, for the above example, I can write</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">w</span><span>=&quot;</span><span style="color:#a3be8c;">wget</span><span>&quot; </span></code></pre> <p>This line goes in your <code>~/.bashrc</code> or <code>~/.zshrc</code> depending on the shell you use. After adding an alias, you need to reload your shell config. This can be done simply by restarting your teminal, or if you don't want to close the current running terminal, you can run the following command:</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">source </span><span style="color:#bf616a;">~</span><span>/.zshrc </span><span style="color:#65737e;"># bash users replace with ~/.bashrc </span></code></pre> <h2 id="some-useful-aliases-i-keep">Some Useful Aliases I Keep</h2> <h3 id="text-editor">Text Editor</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">n</span><span>=&quot;</span><span style="color:#a3be8c;">nvim</span><span>&quot; </span></code></pre> <p>I am quite often in the terminal messing with configuration files and all, meaning I regularly open the text editor. So, I created a single character alias to launch nvim.</p> <h3 id="git-commands">Git Commands</h3> <p>I alias the common Git commands. Some people like to go overboard and add lots of Git related aliases. Do whatever you are comfortable with.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">gcm</span><span>=&quot;</span><span style="color:#a3be8c;">git checkout main</span><span>&quot; </span><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">gp</span><span>=&quot;</span><span style="color:#a3be8c;">git pull</span><span>&quot; </span><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">gpu</span><span>=&quot;</span><span style="color:#a3be8c;">git push</span><span>&quot; </span></code></pre> <h3 id="aliases-for-development-tools">Aliases for Development Tools</h3> <p>I first did this when I was learning Rust.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">ccl</span><span>=&quot;</span><span style="color:#a3be8c;">cargo clean</span><span>&quot; </span><span style="color:#65737e;"># cc conflicts with gcc/cc </span><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">cch</span><span>=&quot;</span><span style="color:#a3be8c;">cargo check</span><span>&quot; </span><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">cb</span><span>=&quot;</span><span style="color:#a3be8c;">cargo build</span><span>&quot; </span><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">cr</span><span>=&quot;</span><span style="color:#a3be8c;">cargo run</span><span>&quot; </span><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">ca</span><span>=&quot;</span><span style="color:#a3be8c;">cargo add</span><span>&quot; </span><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">rn</span><span>=&quot;</span><span style="color:#a3be8c;">rustup override set nightly</span><span>&quot; </span></code></pre> <p>You can set aliases for whichever language or build tools you generally use.</p> <h3 id="ls-commands"><code>ls</code> commands</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">l</span><span>=&quot;</span><span style="color:#a3be8c;">ls -alh --color=tty</span><span>&quot; </span><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">ls</span><span>=&quot;</span><span style="color:#a3be8c;">ls --color=tty</span><span>&quot; </span></code></pre> <p>I simply use <code>l</code> to list files in long format.</p> <h3 id="cat-bat">cat -&gt; bat</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">cat</span><span>=&quot;</span><span style="color:#a3be8c;">bat</span><span>&quot; </span></code></pre> <p><a href="https://github.com/sharkdp/bat">bat</a> is a cat clone with host of new features. The major reason why I use bat is the syntax highlight and line numbering. Using Linux distros for a few years now, I am used to running <code>cat</code> in the terminal, so I aliased it to <code>bat</code>.</p> <h3 id="clear-terminal">Clear Terminal</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">c</span><span>=&quot;</span><span style="color:#a3be8c;">clear</span><span>&quot; </span></code></pre> <p>Yes I am too lazy to type clear so I aliased it to <code>c</code>.</p> <h3 id="copy-to-clipboard">Copy to Clipboard</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">cpy</span><span>=&quot;</span><span style="color:#a3be8c;">xclip -sel clip</span><span>&quot; </span></code></pre> <p>Often you need to copy the output of a command on to the clipboard. If the output is short, you can use your mouse to select text and press Ctrl+Shift+C. However, if the output is long, good luck copying it.</p> <p>With the above alias, I pipe the output of a command to <code>cpy</code> and it will be copied on to the clipboard.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">inxi -F </span><span>| </span><span style="color:#bf616a;">cpy </span><span style="color:#65737e;"># output of inxi -F is copied to clipboard </span></code></pre> <h3 id="youtube-dl-command">Youtube-dl Command</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#96b5b4;">alias </span><span style="color:#8fa1b3;">ytmp3</span><span>=&quot;</span><span style="color:#a3be8c;">youtube-dl --extract-audio --audio-format mp3 --audio-quality 256K --add-metadata --metadata-from-title </span><span style="color:#96b5b4;">\&quot;</span><span style="color:#a3be8c;">%(artist)s - %(title)s</span><span style="color:#96b5b4;">\&quot;</span><span style="color:#a3be8c;"> -o </span><span style="color:#96b5b4;">\&quot;</span><span style="color:#a3be8c;">%(title)s.%(ext)s</span><span style="color:#96b5b4;">\&quot;</span><span>&quot; </span></code></pre> <p>This downloads the audio stream from the supplied link and add metadata to file in <em>Artist - Title</em> format.</p> <h2 id="conclusion">Conclusion</h2> <p>These were just some examples of the aliases I use. You can set more such aliases to make your workflow faster.</p> Arch Linux Package Management Snehit Sah [email protected] http://snehit.dev 2021-05-23T00:00:00+00:00 2021-05-23T00:00:00+00:00 https://snehit.dev/posts/shell/arch-linux-pacman-commands/ <h2 id="introduction">Introduction</h2> <p>Arch Linux comes with a powerful package manager called pacman. Often new users take time to figure out its commands because it does not have the usual 'obvious' commands like apt. So here is a short post about pacman commands.</p> <span id="continue-reading"></span> <p><em>Note : All pacman commands need to be run with superuser privileges. You need to prepend the commands with <code>sudo</code> for them to work. For the sake of brevity, I have omitted <code>sudo</code>.</em></p> <h2 id="installing-packages">Installing Packages</h2> <h3 id="download-and-install">Download and Install</h3> <p><code>-S</code> flag asks pacman to synchronize packages.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -S</span><span> package1 package2 package3 </span></code></pre> <p>will download install specified packages along with their necessary dependencies.</p> <h3 id="selecting-repo-in-case-of-multiple-providers">Selecting Repo in Case of Multiple Providers</h3> <p>By default, package is searched in repos in the order they are listed in <code>/etc/pacman.conf</code>.</p> <p>In case a package is available from more than one source, then you can specify the repo name before package name to select the repo you want to download the package from. For example, I am using Endeavour OS, with Chaotic AUR added to my repo list. So, I can get the <code>polybar</code> package from two sources - EndeavourOS reop and Chaotic AUR repo. Since Endeavour OS repo has a preference in my <code>pacman.conf</code>, pacman will download polybar from that repo. However, if I want to download it from Chaotic AUR, I can run the following command.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -S</span><span> chaotic-aur/polybar </span></code></pre> <h3 id="updating-packages">Updating Packages</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Syu </span></code></pre> <p>will download new package database and then install the packages that have new updates available. This will include your kernel and other core packages too so make sure you have backups ready in case something goes wrong. Timeshift is a popular backup tool.</p> <h3 id="searching-for-a-package">Searching For a Package</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Ss</span><span> search terms </span></code></pre> <p>will search for the supplied terms and provide you with a list of matching entries.</p> <h3 id="download-but-don-t-install">Download But Don't Install</h3> <p>You may want to download packages, but not install them right away. This can be done by using the <code>-w</code> flag with one of the sync commands.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Sw</span><span> reflector </span><span style="color:#65737e;"># downloads reflector but doesn&#39;t install it </span><span style="color:#bf616a;">pacman -Syuw </span><span style="color:#65737e;"># downloads available updates but doesn&#39;t install them </span></code></pre> <h3 id="about-syy-sy-and-syuu">About <code>-Syy</code>, <code>-Sy</code> and <code>-Syuu</code></h3> <p>I edited this post and added this section because this deserves some attention. New users often use <code>-Syyu</code> to update packages. This is not a good practice, since if you frequently update, it will put extra load on the mirrors.</p> <p><code>-Sy</code> will update only those repos that are outdated. <code>-Syy</code> will force update all repos even if they are up to date. So avoid using <code>-Syy</code>. It is meant to be used in case your packaged database is corrupted or has some other issue.</p> <p>Similarly, <code>-Syuu</code> will force package version to be in sync with the repo. In case your mirror has an outdated version of a package, it will be forcefully downgraded. Use <code>-Syu</code> to update packages.</p> <p>And finally, never use <code>-Sy</code> alone. On Arch Linux, <strong>partial upgrades are not supported</strong>. If you do <code>-Sy</code> and then install a package, you will run into a case of partial upgrade and that may lead to problems.</p> <p>In short, use <code>-S</code> to install and <code>-Syu</code> to update.</p> <h3 id="details-for-a-package">Details for a package</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Si</span><span> package-name </span></code></pre> <p>will show details for the supplied package name.</p> <h2 id="removing-packages">Removing packages</h2> <h3 id="remove-a-package">Remove a Package</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -R</span><span> package1 package2 package3 </span></code></pre> <p>will remove the specified packages.</p> <h3 id="remove-along-with-unneeded-dependencies">Remove along with unneeded dependencies</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Rs</span><span> package1 package2 package3 </span></code></pre> <p><code>-s</code> flag instructs pacman to remove any dependencies of the specified packages, that are no longer required by any other package on the system.</p> <h3 id="removing-groups-of-packages">Removing groups of packages</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Rsu</span><span> gnome </span></code></pre> <p>will remove the gnome group, but preserve any packages that are required by one or more packages installed on the system.</p> <h2 id="query-commands">Query commands</h2> <h3 id="list-of-installed-packages">List of installed packages</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Q </span></code></pre> <p>will output the list of installed packages along with their versions.</p> <h3 id="list-packages-no-longer-needed">List packages no longer needed</h3> <p>If you remove packages without using the <code>-s</code> command, then unneeded dependencies can pile up on your system. You can list them with the following command</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Qdtq </span></code></pre> <p>To uninstall them, simply pipe them to <code>pacman -Rs</code> in with the following command</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Qdtq </span><span>| </span><span style="color:#bf616a;">pacman -Rs</span><span> - </span></code></pre> <h3 id="packages-no-longer-part-of-any-repository">Packages no longer part of any repository</h3> <p>Sometimes, when a package is no longer maintained, it is removed from repositories. You may want to remove them since they are most certainly no longer required</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Qm </span><span style="color:#65737e;"># list foreign packages </span><span style="color:#bf616a;">pacman -Qmq </span><span>| </span><span style="color:#bf616a;">pacman -Rs</span><span> - </span><span style="color:#65737e;"># remove foreign packages </span></code></pre> <h3 id="details-for-a-package-1">Details for a package</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Qi</span><span> package-name </span></code></pre> <p>will display information for a the supplied package name. Note that this works only for installed packages.</p> <h3 id="know-owner-of-a-file">Know owner of a file</h3> <p>In case a system file is damaged, reinstalling the relevant package may help you fix it. In such case, you need to know which package owns the file in question.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Qo</span><span> /usr/bin/zsh </span></code></pre> <p>This command tells me package that owns the file I specified.</p> <h3 id="list-explicitly-installed-packages">List explicitly installed packages</h3> <p>To get the list of package installed explicitly, meaning they are not installed as dependencies, run the following command</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Qe </span></code></pre> <p>The "explicitly installed" tag can be modified as described <a href="https://snehit.dev/posts/shell/arch-linux-pacman-commands/#mark-a-package-as-dependency">here</a>.</p> <h3 id="list-packages-installed-as-dependency">List packages installed as dependency</h3> <p>To get the packages that were installed as a dependency, run the following command</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Qd </span></code></pre> <p>Again, this tag can be modified as described <a href="https://snehit.dev/posts/shell/arch-linux-pacman-commands/#mark-a-package-as-explicitly-installed">here</a>.</p> <h3 id="verify-packages">Verify packages</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Qk </span></code></pre> <p>This will check if all the files for the installed packages are available on the system.</p> <h2 id="database-commands">Database commands</h2> <h3 id="mark-a-package-as-explicitly-installed">Mark a package as explicitly installed</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -D --asexplicit</span><span> package-name </span></code></pre> <p>This will mark the package as explicitly installed and this package won't be considered when you run <code>pacman -Qdtq</code> or remove commands unless you explicitly specify the package name as a candidate for removal.</p> <h3 id="mark-a-package-as-dependency">Mark a package as dependency</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -S --asdeps</span><span> package-name </span></code></pre> <p>Works as totally reverse of the previous command. Specified package will be considered for removal and also as unneeded dependency if no package depends on it.</p> <h2 id="file-commands">File commands</h2> <h3 id="list-files-installed-by-a-package">List files installed by a package</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Fl</span><span> package-name </span></code></pre> <p>will show the list of files that a package will install onto your system.</p> <h3 id="search-for-file-or-filepaths">Search for file or filepaths</h3> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -F</span><span> filename </span></code></pre> <p>will search for filename and list the packages that provide a file by that name. This is specially useful when I need to know which package provides a specific header file I need to use.</p> <p><code>-F</code> only accepts complete filenames, without path. To do a regex search, with filepaths and partial names, use the <code>-x</code> flag.</p> <pre data-lang="sh" style="background-color:#2b303b;color:#c0c5ce;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#bf616a;">pacman -Fx</span><span> path/to/file </span></code></pre>